1  /* PR ipa/80732 */
       2  /* { dg-do run } */
       3  /* { dg-options "-ldl -fPIC -rdynamic -O3 -g -pie" } */
       4  /* { dg-require-ifunc "" } */
       5  /* { dg-require-effective-target fma4 } */
       6  /* { dg-require-effective-target fpic } */
       7  /* { dg-require-effective-target pie } */
       8  
       9  #include "fma4-check.h"
      10  
      11  #include <dlfcn.h>
      12  
      13  __attribute__((target_clones("default","fma"),noinline,optimize("fast-math")))
      14  double f1(double a, double b, double c)
      15  {
      16      return a * b + c;
      17  }
      18  
      19  double k1(double a, double b, double c, void **p)
      20  {
      21      *p = f1;
      22      return f1(a, b, c);
      23  }
      24  
      25  __attribute__((target("fma"),optimize("fast-math")))
      26  static double f2_fma(double a, double b, double c)
      27  {
      28      return a * b + c;
      29  }
      30  
      31  __attribute__((optimize("fast-math")))
      32  static double f2_default(double a, double b, double c)
      33  {
      34      return a * b + c;
      35  }
      36  
      37  static __typeof__ (f2_fma)* f2_resolve(void)
      38  {
      39      __builtin_cpu_init ();
      40      if (__builtin_cpu_supports("fma"))
      41          return f2_fma;
      42      else
      43          return f2_default;
      44  }
      45  
      46  double f2(double a, double b, double c) __attribute__((ifunc("f2_resolve")));
      47  
      48  double k2(double a, double b, double c, void **p)
      49  {
      50      *p = f2;
      51      return f2(a, b, c);
      52  }
      53  
      54  double (*initializer) (double, double, double) = { &f1 };
      55  
      56  static void
      57  fma4_test (void)
      58  {
      59      char buffer[256];
      60      const char *expectation = "4.93038e-32, 4.93038e-32, 4.93038e-32";
      61  
      62      volatile double a = 1.0000000000000002;
      63      volatile double b = -0.9999999999999998;
      64      volatile double c = 1.0;
      65  
      66      void *hdl = dlopen(0, RTLD_NOW);
      67  
      68      double (*pf1)(double, double, double) = dlsym(hdl, "f1");
      69      double (*pk1)(double, double, double, void**) = dlsym(hdl, "k1");
      70      double (*_pf1)(double, double, double);
      71  
      72      double v1_1 = pf1(a, b, c);
      73      double v1_2 = pk1(a, b, c, (void**)&_pf1);
      74      double v1_3 = _pf1(a, b, c);
      75      __builtin_sprintf (buffer, "%g, %g, %g", v1_1, v1_2, v1_3);
      76      if (__builtin_strcmp (buffer, expectation) != 0)
      77        __builtin_abort ();
      78  
      79      double (*pf2)(double, double, double) = dlsym(hdl, "f2");
      80      double (*pk2)(double, double, double, void**) = dlsym(hdl, "k2");
      81      double (*_pf2)(double, double, double);
      82  
      83      double v2_1 = pf2(a, b, c);
      84      double v2_2 = pk2(a, b, c, (void**)&_pf2);
      85      double v2_3 = _pf2(a, b, c);
      86      __builtin_sprintf(buffer, "%g, %g, %g", v2_1, v2_2, v2_3);
      87      if (__builtin_strcmp (buffer, expectation) != 0)
      88        __builtin_abort ();
      89  
      90      __builtin_sprintf(buffer, "%g, %g, %g", initializer (a, b, c), v2_2, v2_3);
      91      if (__builtin_strcmp (buffer, expectation) != 0)
      92        __builtin_abort ();
      93  }