1dnl Tries to determine appropriate function names for
2dnl fused multiply-add (fma) and fused multiply-subtract (fms).
3dnl
4dnl Usage: ACX_CXX_FMA(list)
5dnl   where fma_list can contain any of ibm, c99.  If list is
6dnl   blank it will search for a first compatible function.
7dnl
8AC_DEFUN([AX_CXX_FMA], [
9AC_MSG_CHECKING([for fused multiply-add/subtract])
10AC_LANG_PUSH(C++)
11ax_cxx_fma_list=$1
12if test "x$ax_cxx_fma_list" = "x"; then
13  ax_cxx_fma_list="ibm gnu c99 compiler"
14fi
15ax_cxx_fma=
16ax_cxx_fms=
17for name in $ax_cxx_fma_list; do
18  if test "x$ax_cxx_fma" = "x"; then
19    case $name in
20      ibm)
21        # IBM VisualAge C++ __fmadd / __fmsub.
22        AC_RUN_IFELSE([AC_LANG_SOURCE([#include <cmath>
23                       #include <builtins.h>
24                       int main() {
25                         double d = std::ldexp(1.0, -52);
26                         double x = __fmadd(1.0 + d, 1.0 - d, -1.0);
27                         double y = __fmsub(1.0 + d, 1.0 - d, 1.0);
28                         return (x == -d*d && y == -d*d) ? 0 : 1;
29                       }])],
30                      [ax_cxx_fma="__fmadd(x,y,z)"
31                       ax_cxx_fms="__fmsub(x,y,z)"
32                       AC_DEFINE([QD_VACPP_BUILTINS_H], [1],
33                                 [Set to 1 if using VisualAge C++ compiler for __fmadd builtin.])])
34      ;;
35      gnu)
36        # Later gcc (3.4 and later) have __builtin_fma that seems to work.
37        AC_RUN_IFELSE([AC_LANG_SOURCE([#include <cmath>
38                       int main() {
39                         double d = std::ldexp(1.0, -52);
40                         return (__builtin_fma(1.0 + d, 1.0 - d, -1.0) == -d*d ? 0 : 1);
41                       }])],
42                      [ax_cxx_fma="__builtin_fma(x,y,z)"
43                       ax_cxx_fms="__builtin_fma(x,y,-z)"])
44      ;;
45      ia64)
46        # Intel and HP compilers for IA 64 architecture seems to have
47        # _Asm_fma/fms macros.  Not much documentation is available for
48        # these...
49        AC_RUN_IFELSE([AC_LANG_SOURCE([#include <cmath>
50                       int main() {
51                         double d = std::ldexp(1.0, -52);
52                         return (_Asm_fma(2, 1.0 + d, 1.0 - d, -1.0) == -d*d ? 0 : 1);
53                       }])],
54                      [ax_cxx_fma="_Asm_fma(2, x,y,z)"
55                       ax_cxx_fms="_Asm_fms(2, x,y,z)"])
56      ;;
57      c99)
58        # Try C99 fma() function.  Some platforms doesn't seem to implement this
59        # correctly (Apple gcc-3.3 for example).
60        AC_RUN_IFELSE([AC_LANG_SOURCE([#include <cmath>
61                       int main() {
62                         double d = std::ldexp(1.0, -52);
63                         return (fma(1.0 + d, 1.0 - d, -1.0) == -d*d ? 0 : 1);
64                       }])],
65                      [ax_cxx_fma="fma(x,y,z)"
66                       ax_cxx_fms="fma(x,y,-z)"])
67      ;;
68      compiler)
69        # Try relying on the compiler to optimize x * y + z into an fma.
70        # This method is not recommended since if it is inlined it does not
71        # always produce the same correct code.
72        AC_RUN_IFELSE([AC_LANG_SOURCE([#include <cmath>
73                       int main() {
74                         double d = std::ldexp(1.0, -52);
75                         return ( (1.0 + d) * (1.0 - d) - 1.0 == -d*d ? 0 : 1);
76                       }])],
77                       [ax_cxx_fma="((x)*(y) + (z))"
78                        ax_cxx_fms="((x)*(y) - (z))"])
79      ;;
80      *) AC_MSG_ERROR([Unknown option $name to --enable-fma.]) ;;
81    esac
82  fi
83done
84AC_LANG_POP(C++)
85if test "x$ax_cxx_fma" != "x"; then
86  AC_MSG_RESULT([$ax_cxx_fma, $ax_cxx_fms])
87else
88  AC_MSG_RESULT(none)
89fi
90])
91