llvm/libc/utils/MPFRWrapper/MPFRUtils.h

//===-- 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_MPFRWRAPPER_MPFRUTILS_H
#define LLVM_LIBC_UTILS_MPFRWRAPPER_MPFRUTILS_H

#include "src/__support/CPP/type_traits.h"
#include "src/__support/macros/config.h"
#include "test/UnitTest/RoundingModeUtils.h"
#include "test/UnitTest/Test.h"

#include <stdint.h>

namespace LIBC_NAMESPACE_DECL {
namespace testing {
namespace mpfr {

enum class Operation : int {};

ForceRoundingMode;
RoundingMode;

template <typename T> struct BinaryInput {};

template <typename T> struct TernaryInput {};

template <typename T> struct BinaryOutput {};

namespace internal {

template <typename T1, typename T2>
struct AreMatchingBinaryInputAndBinaryOutput {};

AreMatchingBinaryInputAndBinaryOutput<BinaryInput<T>, BinaryOutput<T>>;

template <typename T> struct IsBinaryInput {};

IsBinaryInput<BinaryInput<T>>;

template <typename T> struct IsTernaryInput {};

IsTernaryInput<TernaryInput<T>>;

template <typename T> struct MakeScalarInput : cpp::type_identity<T> {};

MakeScalarInput<BinaryInput<T>>;

MakeScalarInput<TernaryInput<T>>;

template <typename InputType, typename OutputType>
bool compare_unary_operation_single_output(Operation op, InputType input,
                                           OutputType libc_output,
                                           double ulp_tolerance,
                                           RoundingMode rounding);
template <typename T>
bool compare_unary_operation_two_outputs(Operation op, T input,
                                         const BinaryOutput<T> &libc_output,
                                         double ulp_tolerance,
                                         RoundingMode rounding);
template <typename T>
bool compare_binary_operation_two_outputs(Operation op,
                                          const BinaryInput<T> &input,
                                          const BinaryOutput<T> &libc_output,
                                          double ulp_tolerance,
                                          RoundingMode rounding);

template <typename InputType, typename OutputType>
bool compare_binary_operation_one_output(Operation op,
                                         const BinaryInput<InputType> &input,
                                         OutputType libc_output,
                                         double ulp_tolerance,
                                         RoundingMode rounding);

template <typename InputType, typename OutputType>
bool compare_ternary_operation_one_output(Operation op,
                                          const TernaryInput<InputType> &input,
                                          OutputType libc_output,
                                          double ulp_tolerance,
                                          RoundingMode rounding);

template <typename InputType, typename OutputType>
void explain_unary_operation_single_output_error(Operation op, InputType input,
                                                 OutputType match_value,
                                                 double ulp_tolerance,
                                                 RoundingMode rounding);
template <typename T>
void explain_unary_operation_two_outputs_error(
    Operation op, T input, const BinaryOutput<T> &match_value,
    double ulp_tolerance, RoundingMode rounding);
template <typename T>
void explain_binary_operation_two_outputs_error(
    Operation op, const BinaryInput<T> &input,
    const BinaryOutput<T> &match_value, double ulp_tolerance,
    RoundingMode rounding);

template <typename InputType, typename OutputType>
void explain_binary_operation_one_output_error(
    Operation op, const BinaryInput<InputType> &input, OutputType match_value,
    double ulp_tolerance, RoundingMode rounding);

template <typename InputType, typename OutputType>
void explain_ternary_operation_one_output_error(
    Operation op, const TernaryInput<InputType> &input, OutputType match_value,
    double ulp_tolerance, RoundingMode rounding);

template <Operation op, bool silent, typename InputType, typename OutputType>
class MPFRMatcher : public testing::Matcher<OutputType> {};

} // namespace internal

// Return true if the input and ouput types for the operation op are valid
// types.
template <Operation op, typename InputType, typename OutputType>
constexpr bool is_valid_operation() {}

template <Operation op, typename InputType, typename OutputType>
__attribute__((no_sanitize("address"))) cpp::enable_if_t<
    is_valid_operation<op, InputType, OutputType>(),
    internal::MPFRMatcher<op, /*is_silent*/ false, InputType, OutputType>>
get_mpfr_matcher(InputType input, OutputType output_unused,
                 double ulp_tolerance, RoundingMode rounding) {}

template <Operation op, typename InputType, typename OutputType>
__attribute__((no_sanitize("address"))) cpp::enable_if_t<
    is_valid_operation<op, InputType, OutputType>(),
    internal::MPFRMatcher<op, /*is_silent*/ true, InputType, OutputType>>
get_silent_mpfr_matcher(InputType input, OutputType output_unused,
                        double ulp_tolerance, RoundingMode rounding) {}

template <typename T> T round(T x, RoundingMode mode);

template <typename T> bool round_to_long(T x, long &result);
template <typename T> bool round_to_long(T x, RoundingMode mode, long &result);

} // namespace mpfr
} // namespace testing
} // namespace LIBC_NAMESPACE_DECL

// GET_MPFR_DUMMY_ARG is going to be added to the end of GET_MPFR_MACRO as a
// simple way to avoid the compiler warning `gnu-zero-variadic-macro-arguments`.
#define GET_MPFR_DUMMY_ARG(...)

#define GET_MPFR_MACRO(__1, __2, __3, __4, __5, __NAME, ...)

#define EXPECT_MPFR_MATCH_DEFAULT(op, input, match_value, ulp_tolerance)

#define EXPECT_MPFR_MATCH_ROUNDING(op, input, match_value, ulp_tolerance,      \
                                   rounding)

#define EXPECT_MPFR_MATCH(...)

#define TEST_MPFR_MATCH_ROUNDING(op, input, match_value, ulp_tolerance,        \
                                 rounding)

#define TEST_MPFR_MATCH(...)

#define EXPECT_MPFR_MATCH_ALL_ROUNDING(op, input, match_value, ulp_tolerance)

#define TEST_MPFR_MATCH_ROUNDING_SILENTLY(op, input, match_value,              \
                                          ulp_tolerance, rounding)

#define ASSERT_MPFR_MATCH_DEFAULT(op, input, match_value, ulp_tolerance)

#define ASSERT_MPFR_MATCH_ROUNDING(op, input, match_value, ulp_tolerance,      \
                                   rounding)

#define ASSERT_MPFR_MATCH(...)

#define ASSERT_MPFR_MATCH_ALL_ROUNDING(op, input, match_value, ulp_tolerance)

#endif // LLVM_LIBC_UTILS_MPFRWRAPPER_MPFRUTILS_H