//===-- MPFRUtils.h ---------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_UTILS_TESTUTILS_MPFRUTILS_H #define LLVM_LIBC_UTILS_TESTUTILS_MPFRUTILS_H #include "utils/CPP/TypeTraits.h" #include "utils/UnitTest/Test.h" #include namespace __llvm_libc { namespace testing { namespace mpfr { enum class Operation : int { // Operations with take a single floating point number as input // and produce a single floating point number as output. The input // and output floating point numbers are of the same kind. BeginUnaryOperationsSingleOutput, Abs, Ceil, Cos, Exp, Exp2, Floor, Round, Sin, Sqrt, Trunc, EndUnaryOperationsSingleOutput, // Operations which take a single floating point nubmer as input // but produce two outputs. The first ouput is a floating point // number of the same type as the input. The second output is of type // 'int'. BeginUnaryOperationsTwoOutputs, Frexp, // Floating point output, the first output, is the fractional part. EndUnaryOperationsTwoOutputs, // Operations wich take two floating point nubmers of the same type as // input and produce a single floating point number of the same type as // output. BeginBinaryOperationsSingleOutput, Hypot, EndBinaryOperationsSingleOutput, // Operations which take two floating point numbers of the same type as // input and produce two outputs. The first output is a floating nubmer of // the same type as the inputs. The second output is af type 'int'. BeginBinaryOperationsTwoOutputs, RemQuo, // The first output, the floating point output, is the remainder. EndBinaryOperationsTwoOutputs, BeginTernaryOperationsSingleOuput, // TODO: Add operations like fma. EndTernaryOperationsSingleOutput, }; template struct BinaryInput { static_assert( __llvm_libc::cpp::IsFloatingPointType::Value, "Template parameter of BinaryInput must be a floating point type."); using Type = T; T x, y; }; template struct TernaryInput { static_assert( __llvm_libc::cpp::IsFloatingPointType::Value, "Template parameter of TernaryInput must be a floating point type."); using Type = T; T x, y, z; }; template struct BinaryOutput { T f; int i; }; namespace internal { template struct AreMatchingBinaryInputAndBinaryOutput { static constexpr bool value = false; }; template struct AreMatchingBinaryInputAndBinaryOutput, BinaryOutput> { static constexpr bool value = cpp::IsFloatingPointType::Value; }; template bool compareUnaryOperationSingleOutput(Operation op, T input, T libcOutput, double t); template bool compareUnaryOperationTwoOutputs(Operation op, T input, const BinaryOutput &libcOutput, double t); template bool compareBinaryOperationTwoOutputs(Operation op, const BinaryInput &input, const BinaryOutput &libcOutput, double t); template bool compareBinaryOperationOneOutput(Operation op, const BinaryInput &input, T libcOutput, double t); template void explainUnaryOperationSingleOutputError(Operation op, T input, T matchValue, testutils::StreamWrapper &OS); template void explainUnaryOperationTwoOutputsError(Operation op, T input, const BinaryOutput &matchValue, testutils::StreamWrapper &OS); template void explainBinaryOperationTwoOutputsError(Operation op, const BinaryInput &input, const BinaryOutput &matchValue, testutils::StreamWrapper &OS); template void explainBinaryOperationOneOutputError(Operation op, const BinaryInput &input, T matchValue, testutils::StreamWrapper &OS); template class MPFRMatcher : public testing::Matcher { InputType input; OutputType matchValue; double ulpTolerance; public: MPFRMatcher(InputType testInput, double ulpTolerance) : input(testInput), ulpTolerance(ulpTolerance) {} bool match(OutputType libcResult) { matchValue = libcResult; return match(input, matchValue, ulpTolerance); } void explainError(testutils::StreamWrapper &OS) override { explainError(input, matchValue, OS); } private: template static bool match(T in, T out, double tolerance) { return compareUnaryOperationSingleOutput(op, in, out, tolerance); } template static bool match(T in, const BinaryOutput &out, double tolerance) { return compareUnaryOperationTwoOutputs(op, in, out, tolerance); } template static bool match(const BinaryInput &in, T out, double tolerance) { return compareBinaryOperationOneOutput(op, in, out, tolerance); } template static bool match(BinaryInput in, const BinaryOutput &out, double tolerance) { return compareBinaryOperationTwoOutputs(op, in, out, tolerance); } template static bool match(const TernaryInput &in, T out, double tolerance) { // TODO: Implement the comparision function and error reporter. } template static void explainError(T in, T out, testutils::StreamWrapper &OS) { explainUnaryOperationSingleOutputError(op, in, out, OS); } template static void explainError(T in, const BinaryOutput &out, testutils::StreamWrapper &OS) { explainUnaryOperationTwoOutputsError(op, in, out, OS); } template static void explainError(const BinaryInput &in, const BinaryOutput &out, testutils::StreamWrapper &OS) { explainBinaryOperationTwoOutputsError(op, in, out, OS); } template static void explainError(const BinaryInput &in, T out, testutils::StreamWrapper &OS) { explainBinaryOperationOneOutputError(op, in, out, OS); } }; } // namespace internal // Return true if the input and ouput types for the operation op are valid // types. template constexpr bool isValidOperation() { return (Operation::BeginUnaryOperationsSingleOutput < op && op < Operation::EndUnaryOperationsSingleOutput && cpp::IsSame::Value && cpp::IsFloatingPointType::Value) || (Operation::BeginUnaryOperationsTwoOutputs < op && op < Operation::EndUnaryOperationsTwoOutputs && cpp::IsFloatingPointType::Value && cpp::IsSame>::Value) || (Operation::BeginBinaryOperationsSingleOutput < op && op < Operation::EndBinaryOperationsSingleOutput && cpp::IsFloatingPointType::Value && cpp::IsSame>::Value) || (Operation::BeginBinaryOperationsTwoOutputs < op && op < Operation::EndBinaryOperationsTwoOutputs && internal::AreMatchingBinaryInputAndBinaryOutput::value) || (Operation::BeginTernaryOperationsSingleOuput < op && op < Operation::EndTernaryOperationsSingleOutput && cpp::IsFloatingPointType::Value && cpp::IsSame>::Value); } template __attribute__((no_sanitize("address"))) cpp::EnableIfType(), internal::MPFRMatcher> getMPFRMatcher(InputType input, OutputType outputUnused, double t) { return internal::MPFRMatcher(input, t); } } // namespace mpfr } // namespace testing } // namespace __llvm_libc #define EXPECT_MPFR_MATCH(op, input, matchValue, tolerance) \ EXPECT_THAT(matchValue, __llvm_libc::testing::mpfr::getMPFRMatcher( \ input, matchValue, tolerance)) #define ASSERT_MPFR_MATCH(op, input, matchValue, tolerance) \ ASSERT_THAT(matchValue, __llvm_libc::testing::mpfr::getMPFRMatcher( \ input, matchValue, tolerance)) #endif // LLVM_LIBC_UTILS_TESTUTILS_MPFRUTILS_H