(root)/
gcc-13.2.0/
libstdc++-v3/
testsuite/
experimental/
simd/
tests/
bits/
verify.h
       1  // Copyright (C) 2020-2023 Free Software Foundation, Inc.
       2  //
       3  // This file is part of the GNU ISO C++ Library.  This library is free
       4  // software; you can redistribute it and/or modify it under the
       5  // terms of the GNU General Public License as published by the
       6  // Free Software Foundation; either version 3, or (at your option)
       7  // any later version.
       8  //
       9  // This library is distributed in the hope that it will be useful,
      10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12  // GNU General Public License for more details.
      13  //
      14  // You should have received a copy of the GNU General Public License along
      15  // with this library; see the file COPYING3.  If not see
      16  // <http://www.gnu.org/licenses/>.
      17  
      18  #ifndef TESTS_BITS_VERIFY_H_
      19  #define TESTS_BITS_VERIFY_H_
      20  
      21  #include <experimental/simd>
      22  #include <sstream>
      23  #include <iomanip>
      24  #include "ulp.h"
      25  
      26  #ifdef _GLIBCXX_SIMD_HAVE_NEON
      27  // work around PR89357:
      28  #define alignas(...) __attribute__((aligned(__VA_ARGS__)))
      29  #endif
      30  
      31  using schar = signed char;
      32  using uchar = unsigned char;
      33  using ushort = unsigned short;
      34  using uint = unsigned int;
      35  using ulong = unsigned long;
      36  using llong = long long;
      37  using ullong = unsigned long long;
      38  using ldouble = long double;
      39  using wchar = wchar_t;
      40  using char16 = char16_t;
      41  using char32 = char32_t;
      42  
      43  template <class T>
      44    T
      45    make_value_unknown(const T& x)
      46    {
      47      if constexpr (std::is_constructible_v<T, const volatile T&>)
      48        {
      49  	const volatile T& y = x;
      50  	return y;
      51        }
      52      else
      53        {
      54  	T y = x;
      55  	asm("" : "+m"(y));
      56  	return y;
      57        }
      58    }
      59  
      60  class verify
      61  {
      62    const bool m_failed = false;
      63    size_t m_ip = 0;
      64  
      65    template <typename T,
      66  	    typename = decltype(std::declval<std::stringstream&>()
      67  				<< std::declval<const T&>())>
      68      void
      69      print(const T& x, int) const
      70      {
      71        std::stringstream ss;
      72        ss << x;
      73        __builtin_fprintf(stderr, "%s", ss.str().c_str());
      74      }
      75  
      76    template <typename T>
      77      void
      78      print(const T& x, ...) const
      79      {
      80        if constexpr (std::experimental::is_simd_v<T>)
      81  	{
      82  	  std::stringstream ss;
      83  	  if constexpr (std::is_floating_point_v<typename T::value_type>)
      84  	    {
      85  	      ss << '(' << x[0] << " == " << std::hexfloat << x[0]
      86  		<< std::defaultfloat << ')';
      87  	      for (unsigned i = 1; i < x.size(); ++i)
      88  		{
      89  		  ss << (i % 4 == 0 ? ",\n(" : ", (") << x[i]
      90  		    << " == " << std::hexfloat << x[i] << std::defaultfloat
      91  		    << ')';
      92  		}
      93  	    }
      94  	  else
      95  	    {
      96  	      ss << +x[0];
      97  	      for (unsigned i = 1; i < x.size(); ++i)
      98  		{
      99  		  ss << ", " << +x[i];
     100  		}
     101  	    }
     102  	  __builtin_fprintf(stderr, "%s", ss.str().c_str());
     103  	}
     104        else if constexpr (std::experimental::is_simd_mask_v<T>)
     105  	{
     106  	  __builtin_fprintf(stderr, (x[0] ? "[1" : "[0"));
     107  	  for (unsigned i = 1; i < x.size(); ++i)
     108  	    {
     109  	      __builtin_fprintf(stderr, (x[i] ? "1" : "0"));
     110  	    }
     111  	  __builtin_fprintf(stderr, "]");
     112  	}
     113        else
     114  	{
     115  	  print_hex(&x, sizeof(T));
     116  	}
     117      }
     118  
     119    void
     120    print_hex(const void* x, std::size_t n) const
     121    {
     122      __builtin_fprintf(stderr, "0x");
     123      const auto* bytes = static_cast<const unsigned char*>(x);
     124      for (std::size_t i = 0; i < n; ++i)
     125        {
     126  	__builtin_fprintf(stderr, (i && i % 4 == 0) ? "'%02x" : "%02x",
     127  			  bytes[i]);
     128        }
     129    }
     130  
     131  public:
     132    template <typename... Ts>
     133      [[gnu::always_inline]]
     134      verify(bool ok, const char* file, const int line,
     135  	   const char* func, const char* cond, const Ts&... extra_info)
     136      : m_failed(!ok), m_ip(get_ip())
     137      {
     138        if (m_failed)
     139  	[&] {
     140  	  __builtin_fprintf(stderr, "%s:%d: (%s):\nInstruction Pointer: %zx\n"
     141  				    "Assertion '%s' failed.\n",
     142  			    file, line, func, m_ip, cond);
     143  	  (print(extra_info, int()), ...);
     144  	}();
     145      }
     146  
     147    [[gnu::always_inline]] ~verify()
     148    {
     149      if (m_failed)
     150        {
     151  	__builtin_fprintf(stderr, "\n");
     152  	__builtin_abort();
     153        }
     154    }
     155  
     156    template <typename T>
     157      [[gnu::always_inline]]
     158      const verify&
     159      operator<<(const T& x) const
     160      {
     161        if (m_failed)
     162  	print(x, int());
     163        return *this;
     164      }
     165  
     166    template <typename... Ts>
     167      [[gnu::always_inline]]
     168      const verify&
     169      on_failure(const Ts&... xs) const
     170      {
     171        if (m_failed)
     172  	[&] { (print(xs, int()), ...); }();
     173        return *this;
     174      }
     175  
     176    [[gnu::always_inline]] static inline
     177    size_t
     178    get_ip()
     179    {
     180      size_t _ip = 0;
     181  #ifdef __x86_64__
     182      asm volatile("lea 0(%%rip),%0" : "=r"(_ip));
     183  #elif defined __i386__
     184      asm volatile("1: movl $1b,%0" : "=r"(_ip));
     185  #elif defined __arm__
     186      asm volatile("mov %0,pc" : "=r"(_ip));
     187  #elif defined __aarch64__
     188      asm volatile("adr %0,." : "=r"(_ip));
     189  #endif
     190      return _ip;
     191    }
     192  };
     193  
     194  #if __FLT_EVAL_METHOD__ != 0
     195  template <typename T>
     196    [[gnu::always_inline]] inline decltype(auto)
     197    force_fp_truncation(const T& x)
     198    {
     199      namespace stdx = std::experimental;
     200      if constexpr (stdx::is_simd_v<T>)
     201        {
     202  	using U = typename T::value_type;
     203  	if constexpr (std::is_floating_point_v<typename T::value_type>
     204  		      && sizeof(U) <= 8 && (sizeof(T) < 16 || std::is_same_v<
     205  		  T, stdx::fixed_size_simd<U, T::size()>>))
     206  	  {
     207  	    T y = x;
     208  	    asm("" : "+m"(y));
     209  	    return y;
     210  	  }
     211  	else
     212  	  return x;
     213        }
     214      else if constexpr (std::is_floating_point_v<T> && sizeof(T) <= 8)
     215        {
     216  	T y = x;
     217  	asm("" : "+m"(y));
     218  	return y;
     219        }
     220      else
     221        return x;
     222    }
     223  
     224  #define COMPARE(_a, _b)                                                        \
     225    [&](auto&& _aa, auto&& _bb) {                                                \
     226      return verify(std::experimental::all_of(_aa == _bb), __FILE__, __LINE__,   \
     227  		  __PRETTY_FUNCTION__, #_a " == " #_b, #_a " = ", _aa,         \
     228  		  "\n" #_b " = ", _bb);                                        \
     229    }(force_fp_truncation(_a), force_fp_truncation(_b))
     230  #else
     231  #define COMPARE(_a, _b)                                                        \
     232    [&](auto&& _aa, auto&& _bb) {                                                \
     233      return verify(std::experimental::all_of(_aa == _bb), __FILE__, __LINE__,   \
     234  		  __PRETTY_FUNCTION__, #_a " == " #_b, #_a " = ", _aa,         \
     235  		  "\n" #_b " = ", _bb);                                        \
     236    }((_a), (_b))
     237  #endif
     238  
     239  #define VERIFY(_test)                                                          \
     240    verify(_test, __FILE__, __LINE__, __PRETTY_FUNCTION__, #_test)
     241  
     242    // ulp_distance_signed can raise FP exceptions and thus must be conditionally
     243    // executed
     244  #define ULP_COMPARE(_a, _b, _allowed_distance)                                 \
     245    [&](auto&& _aa, auto&& _bb) {                                                \
     246      const bool success = std::experimental::all_of(                            \
     247        vir::test::ulp_distance(_aa, _bb) <= (_allowed_distance));               \
     248      return verify(success, __FILE__, __LINE__, __PRETTY_FUNCTION__,            \
     249  		  #_a " ~~ " #_b, #_a " = ", _aa, "\n" #_b " = ", _bb,         \
     250  		  "\ndistance = ",                                             \
     251  		  success ? 0 : vir::test::ulp_distance_signed(_aa, _bb));     \
     252    }((_a), (_b))
     253  
     254  namespace vir {
     255    namespace test
     256    {
     257      template <typename T>
     258        inline T _S_fuzzyness = 0;
     259  
     260      template <typename T>
     261        void
     262        setFuzzyness(T x)
     263        { _S_fuzzyness<T> = x; }
     264    } // namespace test
     265  } // namespace vir
     266  
     267  #define FUZZY_COMPARE(_a, _b)                                                  \
     268    ULP_COMPARE(                                                                 \
     269      _a, _b,                                                                    \
     270      vir::test::_S_fuzzyness<vir::test::value_type_t<decltype((_a) + (_b))>>)
     271  
     272  template <typename V>
     273    void
     274    test();
     275  
     276  template <typename V>
     277    void
     278    invoke_test(...)
     279    {}
     280  
     281  template <typename V, typename = decltype(V())>
     282    void
     283    invoke_test(int)
     284    {
     285      test<V>();
     286      __builtin_fprintf(stderr, "PASS: %s\n", __PRETTY_FUNCTION__);
     287    }
     288  
     289  #endif  // TESTS_BITS_VERIFY_H_