Target FP: Make use of MPFR if available
authorUlrich Weigand <ulrich.weigand@de.ibm.com>
Wed, 22 Nov 2017 12:53:43 +0000 (13:53 +0100)
committerUlrich Weigand <ulrich.weigand@de.ibm.com>
Wed, 22 Nov 2017 12:53:43 +0000 (13:53 +0100)
This second patch introduces mfpr_float_ops, an new implementation
of target_float_ops.  This implements precise emulation of target
floating-point formats using the MPFR library.  This is then used
to perform operations on types that do not match any host type.

Note that use of MPFR is still not required.  The patch adds
a configure option --with-mpfr similar to --with-expat.  If use of
MPFR is disabled via the option or MPFR is not available, code will
fall back to current behavior.  This means that operations on types
that do not match any host type will be implemented on the host
long double type instead.

A new test case verifies that we can correctly print the largest
__float128 value now.

gdb/ChangeLog:
2017-11-22  Ulrich Weigand  <uweigand@de.ibm.com>

* NEWS: Document use of GNU MPFR.
* README: Likewise.

* Makefile.in (LIBMPFR): Add define.
(CLIBS): Add $(LIBMPFR).
* configure.ac: Add --with-mpfr configure option.
* configure: Regenerate.
* config.in: Regenerate.

* target-float.c [HAVE_LIBMPFR]: Include <mpfr.h>.
(class mpfr_float_ops): New type.
(mpfr_float_ops::from_target): Two new overloaded functions.
(mpfr_float_ops::to_target): Likewise.
(mpfr_float_ops::to_string): New function.
(mpfr_float_ops::from_string): Likewise.
(mpfr_float_ops::to_longest): Likewise.
(mpfr_float_ops::from_longest): Likewise.
(mpfr_float_ops::from_ulongest): Likewise.
(mpfr_float_ops::to_host_double): Likewise.
(mpfr_float_ops::from_host_double): Likewise.
(mpfr_float_ops::convert): Likewise.
(mpfr_float_ops::binop): Likewise.
(mpfr_float_ops::compare): Likewise.
(get_target_float_ops): Use mpfr_float_ops if available.

gdb/doc/ChangeLog:
2017-11-22  Ulrich Weigand  <uweigand@de.ibm.com>

* gdb.texinfo (Requirements): Document use of GNU MPFR.

gdb/testsuite/ChangeLog:
2017-11-22  Ulrich Weigand  <uweigand@de.ibm.com>

* gdb.base/float128.c (large128): New variable.
* gdb.base/float128.exp: Add test to print largest __float128 value.

13 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/NEWS
gdb/README
gdb/config.in
gdb/configure
gdb/configure.ac
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/target-float.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/float128.c
gdb/testsuite/gdb.base/float128.exp

index b330c7b1cf524da719f87e6ab0cc3178b5866124..56233006cab87528d00346c0a40625f8681ddac6 100644 (file)
@@ -1,3 +1,30 @@
+2017-11-22  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * NEWS: Document use of GNU MPFR.
+       * README: Likewise.
+
+       * Makefile.in (LIBMPFR): Add define.
+       (CLIBS): Add $(LIBMPFR).
+       * configure.ac: Add --with-mpfr configure option.
+       * configure: Regenerate.
+       * config.in: Regenerate.
+
+       * target-float.c [HAVE_LIBMPFR]: Include <mpfr.h>.
+       (class mpfr_float_ops): New type.
+       (mpfr_float_ops::from_target): Two new overloaded functions.
+       (mpfr_float_ops::to_target): Likewise.
+       (mpfr_float_ops::to_string): New function.
+       (mpfr_float_ops::from_string): Likewise.
+       (mpfr_float_ops::to_longest): Likewise.
+       (mpfr_float_ops::from_longest): Likewise.
+       (mpfr_float_ops::from_ulongest): Likewise.
+       (mpfr_float_ops::to_host_double): Likewise.
+       (mpfr_float_ops::from_host_double): Likewise.
+       (mpfr_float_ops::convert): Likewise.
+       (mpfr_float_ops::binop): Likewise.
+       (mpfr_float_ops::compare): Likewise.
+       (get_target_float_ops): Use mpfr_float_ops if available.
+
 2017-11-22  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * target-float.c: Do not include <math.h>.
index a3bfbf93e1f80e6a367940e6779c401973fdf62a..78a43c52d25efdcbfb7473e20c5676ff6dfb7a9b 100644 (file)
@@ -194,6 +194,9 @@ LIBBABELTRACE = @LIBBABELTRACE@
 # Where is libipt?  This will be empty if libipt was not available.
 LIBIPT = @LIBIPT@
 
+# Where is libmpfr?  This will be empty if libmpfr was not available.
+LIBMPFR = @LIBMPFR@
+
 WARN_CFLAGS = @WARN_CFLAGS@
 WERROR_CFLAGS = @WERROR_CFLAGS@
 GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -703,7 +706,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(ZLIB) $(INTL) $(LIBIBERTY) $(LIBD
        $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) \
        @LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
        $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
-       $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV)
+       $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR)
 CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
        $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
 
index dc070facb86dfe1fd50ecdc9bd6d40515bec9fc4..a239624b827fa7d3ef7fb992c72d88d89ba6237c 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,11 @@
 
 *** Changes since GDB 8.0
 
+* GDB now uses the GNU MPFR library, if available, to emulate target
+  floating-point arithmetic during expression evaluation when the target
+  uses different floating-point formats than the host.  At least version
+  3.1 of GNU MPFR is required.
+
 * GDB now supports access to the guarded-storage-control registers and the
   software-based guarded-storage broadcast control registers on IBM z14.
 
index d485536ecfe30667cb7b9a28172a46fa9aef0a16..e43887ffcdfa749290fc01ba1b304d855a35d2dc 100644 (file)
@@ -89,6 +89,14 @@ features.  Expat will be linked in if it is available at build time, or
 those features will be disabled.  The latest version of Expat should be
 available from `http://expat.sourceforge.net'.
 
+   GDB uses GNU MPFR, a library for multiple-precision floating-point
+computation with correct rounding, to emulate target floating-point
+arithmetic during expression evaluation when the target uses different
+floating-point formats than the host.  MPFR will be linked in if it is
+available at build time.  If GNU MPFR it is not available, GDB will fall
+back to using host floating-point arithmetic.  The latest version of
+GNU MPFR should be available from `http://www.mpfr.org'.
+
    GDB can be used as a cross-debugger, running on a machine of one
 type while debugging a program running on a machine of another type.
 See below.
@@ -475,6 +483,15 @@ prefer; but you may abbreviate option names if you use `--'.
      have libexpat installed, you can  get the latest version from
      http://expat.sourceforge.net.
 
+`--with-mpfr'
+     Build GDB with the GNU MPFR library.  (Done by default if
+     GNU MPFR is installed and found at configure time.)  This library
+     is used to emulate target floating-point arithmetic during expression
+     evaluation when the target uses different floating-point formats than
+     the host.  If GNU MPFR is not available, GDB will fall back to using
+     host floating-point arithmetic.  If your host does not have GNU MPFR
+     installed, you can get the latest version from http://www.mpfr.org.
+
 `--with-python[=PATH]'
      Build GDB with Python scripting support.  (Done by default if
      libpython is present and found at configure time.)  Python makes
index 904c604cc2ec39c5240f54398960c2466b8d164e..60cdc77cceb987619534ea9b7200b08dcb8a6483 100644 (file)
 /* Define to 1 if you have the `mcheck' library (-lmcheck). */
 #undef HAVE_LIBMCHECK
 
+/* Define if you have the mpfr library. */
+#undef HAVE_LIBMPFR
+
 /* Define if Python 2.4 is being used. */
 #undef HAVE_LIBPYTHON2_4
 
index def194dceea3df8b2ba6a999e47ce36137939d00..55544fb4bf8e1140f6b78f512f201d781ca99b66 100755 (executable)
@@ -682,6 +682,9 @@ PYTHON_LIBS
 PYTHON_CPPFLAGS
 PYTHON_CFLAGS
 python_prog_path
+LTLIBMPFR
+LIBMPFR
+HAVE_LIBMPFR
 LTLIBEXPAT
 LIBEXPAT
 HAVE_LIBEXPAT
@@ -838,6 +841,8 @@ with_system_readline
 with_jit_reader_dir
 with_expat
 with_libexpat_prefix
+with_mpfr
+with_libmpfr_prefix
 with_python
 with_guile
 enable_libmcheck
@@ -1560,6 +1565,9 @@ Optional Packages:
   --with-expat            include expat support (auto/yes/no)
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
   --without-libexpat-prefix     don't search for libexpat in includedir and libdir
+  --with-mpfr             include MPFR support (auto/yes/no)
+  --with-libmpfr-prefix[=DIR]  search for libmpfr in DIR/include and DIR/lib
+  --without-libmpfr-prefix     don't search for libmpfr in includedir and libdir
   --with-python[=PYTHON]  include python support
                           (auto/yes/no/<python-program>)
   --with-guile[=GUILE]    include guile support
@@ -9643,6 +9651,497 @@ done
   fi
 fi
 
+
+# Check whether --with-mpfr was given.
+if test "${with_mpfr+set}" = set; then :
+  withval=$with_mpfr;
+else
+  with_mpfr=auto
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use MPFR" >&5
+$as_echo_n "checking whether to use MPFR... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_mpfr" >&5
+$as_echo "$with_mpfr" >&6; }
+
+if test "${with_mpfr}" = no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MPFR support disabled; some features may be unavailable." >&5
+$as_echo "$as_me: WARNING: MPFR support disabled; some features may be unavailable." >&2;}
+  HAVE_LIBMPFR=no
+else
+
+
+
+
+
+
+
+
+    use_additional=yes
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+
+# Check whether --with-libmpfr-prefix was given.
+if test "${with_libmpfr_prefix+set}" = set; then :
+  withval=$with_libmpfr_prefix;
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/lib"
+      fi
+    fi
+
+fi
+
+      LIBMPFR=
+  LTLIBMPFR=
+  INCMPFR=
+  rpathdirs=
+  ltrpathdirs=
+  names_already_handled=
+  names_next_round='mpfr '
+  while test -n "$names_next_round"; do
+    names_this_round="$names_next_round"
+    names_next_round=
+    for name in $names_this_round; do
+      already_handled=
+      for n in $names_already_handled; do
+        if test "$n" = "$name"; then
+          already_handled=yes
+          break
+        fi
+      done
+      if test -z "$already_handled"; then
+        names_already_handled="$names_already_handled $name"
+                        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+        eval value=\"\$HAVE_LIB$uppername\"
+        if test -n "$value"; then
+          if test "$value" = yes; then
+            eval value=\"\$LIB$uppername\"
+            test -z "$value" || LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$value"
+            eval value=\"\$LTLIB$uppername\"
+            test -z "$value" || LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }$value"
+          else
+                                    :
+          fi
+        else
+                              found_dir=
+          found_la=
+          found_so=
+          found_a=
+          if test $use_additional = yes; then
+            if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+              found_dir="$additional_libdir"
+              found_so="$additional_libdir/lib$name.$shlibext"
+              if test -f "$additional_libdir/lib$name.la"; then
+                found_la="$additional_libdir/lib$name.la"
+              fi
+            else
+              if test -f "$additional_libdir/lib$name.$libext"; then
+                found_dir="$additional_libdir"
+                found_a="$additional_libdir/lib$name.$libext"
+                if test -f "$additional_libdir/lib$name.la"; then
+                  found_la="$additional_libdir/lib$name.la"
+                fi
+              fi
+            fi
+          fi
+          if test "X$found_dir" = "X"; then
+            for x in $LDFLAGS $LTLIBMPFR; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+              case "$x" in
+                -L*)
+                  dir=`echo "X$x" | sed -e 's/^X-L//'`
+                  if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+                    found_dir="$dir"
+                    found_so="$dir/lib$name.$shlibext"
+                    if test -f "$dir/lib$name.la"; then
+                      found_la="$dir/lib$name.la"
+                    fi
+                  else
+                    if test -f "$dir/lib$name.$libext"; then
+                      found_dir="$dir"
+                      found_a="$dir/lib$name.$libext"
+                      if test -f "$dir/lib$name.la"; then
+                        found_la="$dir/lib$name.la"
+                      fi
+                    fi
+                  fi
+                  ;;
+              esac
+              if test "X$found_dir" != "X"; then
+                break
+              fi
+            done
+          fi
+          if test "X$found_dir" != "X"; then
+                        LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }-L$found_dir -l$name"
+            if test "X$found_so" != "X"; then
+                                                        if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+                                LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_so"
+              else
+                                                                                haveit=
+                for x in $ltrpathdirs; do
+                  if test "X$x" = "X$found_dir"; then
+                    haveit=yes
+                    break
+                  fi
+                done
+                if test -z "$haveit"; then
+                  ltrpathdirs="$ltrpathdirs $found_dir"
+                fi
+                                if test "$hardcode_direct" = yes; then
+                                                      LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_so"
+                else
+                  if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+                                                            LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_so"
+                                                            haveit=
+                    for x in $rpathdirs; do
+                      if test "X$x" = "X$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      rpathdirs="$rpathdirs $found_dir"
+                    fi
+                  else
+                                                                                haveit=
+                    for x in $LDFLAGS $LIBMPFR; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                      if test "X$x" = "X-L$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-L$found_dir"
+                    fi
+                    if test "$hardcode_minus_L" != no; then
+                                                                                        LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_so"
+                    else
+                                                                                                                                                                                LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-l$name"
+                    fi
+                  fi
+                fi
+              fi
+            else
+              if test "X$found_a" != "X"; then
+                                LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_a"
+              else
+                                                LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-L$found_dir -l$name"
+              fi
+            fi
+                        additional_includedir=
+            case "$found_dir" in
+              */lib | */lib/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+                additional_includedir="$basedir/include"
+                ;;
+            esac
+            if test "X$additional_includedir" != "X"; then
+                                                                                                                if test "X$additional_includedir" != "X/usr/include"; then
+                haveit=
+                if test "X$additional_includedir" = "X/usr/local/include"; then
+                  if test -n "$GCC"; then
+                    case $host_os in
+                      linux*) haveit=yes;;
+                    esac
+                  fi
+                fi
+                if test -z "$haveit"; then
+                  for x in $CPPFLAGS $INCMPFR; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                    if test "X$x" = "X-I$additional_includedir"; then
+                      haveit=yes
+                      break
+                    fi
+                  done
+                  if test -z "$haveit"; then
+                    if test -d "$additional_includedir"; then
+                                            INCMPFR="${INCMPFR}${INCMPFR:+ }-I$additional_includedir"
+                    fi
+                  fi
+                fi
+              fi
+            fi
+                        if test -n "$found_la"; then
+                                                        save_libdir="$libdir"
+              case "$found_la" in
+                */* | *\\*) . "$found_la" ;;
+                *) . "./$found_la" ;;
+              esac
+              libdir="$save_libdir"
+                            for dep in $dependency_libs; do
+                case "$dep" in
+                  -L*)
+                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                                                                                                                                                                if test "X$additional_libdir" != "X/usr/lib"; then
+                      haveit=
+                      if test "X$additional_libdir" = "X/usr/local/lib"; then
+                        if test -n "$GCC"; then
+                          case $host_os in
+                            linux*) haveit=yes;;
+                          esac
+                        fi
+                      fi
+                      if test -z "$haveit"; then
+                        haveit=
+                        for x in $LDFLAGS $LIBMPFR; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                                                        LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-L$additional_libdir"
+                          fi
+                        fi
+                        haveit=
+                        for x in $LDFLAGS $LTLIBMPFR; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                                                        LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }-L$additional_libdir"
+                          fi
+                        fi
+                      fi
+                    fi
+                    ;;
+                  -R*)
+                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
+                    if test "$enable_rpath" != no; then
+                                                                  haveit=
+                      for x in $rpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        rpathdirs="$rpathdirs $dir"
+                      fi
+                                                                  haveit=
+                      for x in $ltrpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        ltrpathdirs="$ltrpathdirs $dir"
+                      fi
+                    fi
+                    ;;
+                  -l*)
+                                        names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    ;;
+                  *.la)
+                                                                                names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+                    ;;
+                  *)
+                                        LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$dep"
+                    LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }$dep"
+                    ;;
+                esac
+              done
+            fi
+          else
+                                                            LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-l$name"
+            LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }-l$name"
+          fi
+        fi
+      fi
+    done
+  done
+  if test "X$rpathdirs" != "X"; then
+    if test -n "$hardcode_libdir_separator"; then
+                        alldirs=
+      for found_dir in $rpathdirs; do
+        alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+      done
+            acl_save_libdir="$libdir"
+      libdir="$alldirs"
+      eval flag=\"$hardcode_libdir_flag_spec\"
+      libdir="$acl_save_libdir"
+      LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$flag"
+    else
+            for found_dir in $rpathdirs; do
+        acl_save_libdir="$libdir"
+        libdir="$found_dir"
+        eval flag=\"$hardcode_libdir_flag_spec\"
+        libdir="$acl_save_libdir"
+        LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$flag"
+      done
+    fi
+  fi
+  if test "X$ltrpathdirs" != "X"; then
+            for found_dir in $ltrpathdirs; do
+      LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }-R$found_dir"
+    done
+  fi
+
+
+        ac_save_CPPFLAGS="$CPPFLAGS"
+
+  for element in $INCMPFR; do
+    haveit=
+    for x in $CPPFLAGS; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+      if test "X$x" = "X$element"; then
+        haveit=yes
+        break
+      fi
+    done
+    if test -z "$haveit"; then
+      CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+    fi
+  done
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libmpfr" >&5
+$as_echo_n "checking for libmpfr... " >&6; }
+if test "${ac_cv_libmpfr+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    ac_save_LIBS="$LIBS"
+    LIBS="$LIBS $LIBMPFR"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <mpfr.h>
+int
+main ()
+{
+mpfr_exp_t exp; mpfr_t x;
+                        mpfr_frexp (&exp, x, x, MPFR_RNDN);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_libmpfr=yes
+else
+  ac_cv_libmpfr=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LIBS="$ac_save_LIBS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libmpfr" >&5
+$as_echo "$ac_cv_libmpfr" >&6; }
+  if test "$ac_cv_libmpfr" = yes; then
+    HAVE_LIBMPFR=yes
+
+$as_echo "#define HAVE_LIBMPFR 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libmpfr" >&5
+$as_echo_n "checking how to link with libmpfr... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBMPFR" >&5
+$as_echo "$LIBMPFR" >&6; }
+  else
+    HAVE_LIBMPFR=no
+            CPPFLAGS="$ac_save_CPPFLAGS"
+    LIBMPFR=
+    LTLIBMPFR=
+  fi
+
+
+
+
+
+
+  if test "$HAVE_LIBMPFR" != yes; then
+    if test "$with_mpfr" = yes; then
+      as_fn_error "MPFR is missing or unusable" "$LINENO" 5
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MPFR is missing or unusable; some features may be unavailable." >&5
+$as_echo "$as_me: WARNING: MPFR is missing or unusable; some features may be unavailable." >&2;}
+    fi
+  fi
+fi
+
 # --------------------- #
 # Check for libpython.  #
 # --------------------- #
index b909217c77da59c7b304b2dfa812cf5b629569ba..d43899c4146b2017ef009a07deb0b7fd7b6382e4 100644 (file)
@@ -695,6 +695,28 @@ else
   fi
 fi
 
+AC_ARG_WITH(mpfr,
+  AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
+  [], [with_mpfr=auto])
+AC_MSG_CHECKING([whether to use MPFR])
+AC_MSG_RESULT([$with_mpfr])
+
+if test "${with_mpfr}" = no; then
+  AC_MSG_WARN([MPFR support disabled; some features may be unavailable.])
+  HAVE_LIBMPFR=no
+else
+  AC_LIB_HAVE_LINKFLAGS([mpfr], [], [#include <mpfr.h>],
+                       [mpfr_exp_t exp; mpfr_t x;
+                        mpfr_frexp (&exp, x, x, MPFR_RNDN);])
+  if test "$HAVE_LIBMPFR" != yes; then
+    if test "$with_mpfr" = yes; then
+      AC_MSG_ERROR([MPFR is missing or unusable])
+    else
+      AC_MSG_WARN([MPFR is missing or unusable; some features may be unavailable.])
+    fi
+  fi
+fi
+
 # --------------------- #
 # Check for libpython.  #
 # --------------------- #
index 2d8f5afb3d82001455b9b2ab49e33bd15dafc6aa..81af3aa632fecb03022b8136d2da38443c8a8648 100644 (file)
@@ -1,3 +1,8 @@
+2017-11-22  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * gdb.texinfo (Requirements): Document use of GNU MPFR.
+
+
 2017-11-16  Phil Muldoon  <pmuldoon@redhat.com>
 
        * python.texi (Basic Python): Add rbreak documentation.
index 29d47892fc7aa28feb4c862f897cdbccc92d5eff..ab05a3718d6e3596f2844392f0eae0dc608ba4ab 100644 (file)
@@ -34270,6 +34270,21 @@ Branch trace (@pxref{Branch Trace Format},
 @pxref{Branch Trace Configuration Format})
 @end itemize
 
+@item MPFR
+@anchor{MPFR}
+@value{GDBN} can use the GNU MPFR multiple-precision floating-point
+library.  This library may be included with your operating system
+distribution; if it is not, you can get the latest version from
+@url{http://www.mpfr.org}.  The @file{configure} script will search
+for this library in several standard locations; if it is installed
+in an unusual path, you can use the @option{--with-libmpfr-prefix}
+option to specify its location.
+
+GNU MPFR is used to emulate target floating-point arithmetic during
+expression evaluation when the target uses different floating-point
+formats than the host.  If GNU MPFR it is not available, @value{GDBN}
+will fall back to using host floating-point arithmetic.
+
 @item zlib
 @cindex compressed debug sections 
 @value{GDBN} will use the @samp{zlib} library, if available, to read
index 8f1b9f644326d9fe7ec2befbe2cd82bbdde374ee..32237ec9d9364b151cf1ba7d1a7e974a8d89411e 100644 (file)
@@ -1142,6 +1142,569 @@ host_float_ops<T>::compare (const gdb_byte *x, const struct type *type_x,
 }
 
 
+/* Implementation of target_float_ops using the MPFR library
+   mpfr_t as intermediate type.  */
+
+#ifdef HAVE_LIBMPFR
+
+#include <mpfr.h>
+
+class mpfr_float_ops : public target_float_ops
+{
+public:
+  std::string to_string (const gdb_byte *addr, const struct type *type,
+                        const char *format) const override;
+  bool from_string (gdb_byte *addr, const struct type *type,
+                   const std::string &string) const override;
+
+  LONGEST to_longest (const gdb_byte *addr,
+                     const struct type *type) const override;
+  void from_longest (gdb_byte *addr, const struct type *type,
+                    LONGEST val) const override;
+  void from_ulongest (gdb_byte *addr, const struct type *type,
+                     ULONGEST val) const override;
+  double to_host_double (const gdb_byte *addr,
+                        const struct type *type) const override;
+  void from_host_double (gdb_byte *addr, const struct type *type,
+                        double val) const override;
+  void convert (const gdb_byte *from, const struct type *from_type,
+               gdb_byte *to, const struct type *to_type) const override;
+
+  void binop (enum exp_opcode opcode,
+             const gdb_byte *x, const struct type *type_x,
+             const gdb_byte *y, const struct type *type_y,
+             gdb_byte *res, const struct type *type_res) const override;
+  int compare (const gdb_byte *x, const struct type *type_x,
+              const gdb_byte *y, const struct type *type_y) const override;
+
+private:
+  /* Local wrapper class to handle mpfr_t initalization and cleanup.  */
+  class gdb_mpfr
+  {
+  public:
+    mpfr_t val;
+
+    gdb_mpfr (const struct type *type)
+    {
+      const struct floatformat *fmt = floatformat_from_type (type);
+      mpfr_init2 (val, floatformat_precision (fmt));
+    }
+
+    gdb_mpfr (const gdb_mpfr &source)
+    {
+      mpfr_init2 (val, mpfr_get_prec (source.val));
+    }
+
+    ~gdb_mpfr ()
+    {
+      mpfr_clear (val);
+    }
+  };
+
+  void from_target (const struct floatformat *fmt,
+               const gdb_byte *from, gdb_mpfr &to) const;
+  void from_target (const struct type *type,
+               const gdb_byte *from, gdb_mpfr &to) const;
+
+  void to_target (const struct type *type,
+                 const gdb_mpfr &from, gdb_byte *to) const;
+  void to_target (const struct floatformat *fmt,
+                 const gdb_mpfr &from, gdb_byte *to) const;
+};
+
+
+/* Convert TO/FROM target floating-point format to mpfr_t.  */
+
+void
+mpfr_float_ops::from_target (const struct floatformat *fmt,
+                            const gdb_byte *orig_from, gdb_mpfr &to) const
+{
+  const gdb_byte *from = orig_from;
+  mpfr_exp_t exponent;
+  unsigned long mant;
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+  int special_exponent;                /* It's a NaN, denorm or zero.  */
+  enum floatformat_byteorders order;
+  unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+  enum float_kind kind;
+
+  gdb_assert (fmt->totalsize
+             <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+
+  /* Handle non-numbers.  */
+  kind = floatformat_classify (fmt, from);
+  if (kind == float_infinite)
+    {
+      mpfr_set_inf (to.val, floatformat_is_negative (fmt, from) ? -1 : 1);
+      return;
+    }
+  if (kind == float_nan)
+    {
+      mpfr_set_nan (to.val);
+      return;
+    }
+
+  order = floatformat_normalize_byteorder (fmt, from, newfrom);
+
+  if (order != fmt->byteorder)
+    from = newfrom;
+
+  if (fmt->split_half)
+    {
+      gdb_mpfr top (to), bot (to);
+
+      from_target (fmt->split_half, from, top);
+      /* Preserve the sign of 0, which is the sign of the top half.  */
+      if (mpfr_zero_p (top.val))
+       {
+         mpfr_set (to.val, top.val, MPFR_RNDN);
+         return;
+       }
+      from_target (fmt->split_half,
+              from + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2, bot);
+      mpfr_add (to.val, top.val, bot.val, MPFR_RNDN);
+      return;
+    }
+
+  exponent = get_field (from, order, fmt->totalsize, fmt->exp_start,
+                       fmt->exp_len);
+  /* Note that if exponent indicates a NaN, we can't really do anything useful
+     (not knowing if the host has NaN's, or how to build one).  So it will
+     end up as an infinity or something close; that is OK.  */
+
+  mant_bits_left = fmt->man_len;
+  mant_off = fmt->man_start;
+  mpfr_set_zero (to.val, 0);
+
+  special_exponent = exponent == 0 || exponent == fmt->exp_nan;
+
+  /* Don't bias NaNs.  Use minimum exponent for denorms.  For
+     simplicity, we don't check for zero as the exponent doesn't matter.
+     Note the cast to int; exp_bias is unsigned, so it's important to
+     make sure the operation is done in signed arithmetic.  */
+  if (!special_exponent)
+    exponent -= fmt->exp_bias;
+  else if (exponent == 0)
+    exponent = 1 - fmt->exp_bias;
+
+  /* Build the result algebraically.  Might go infinite, underflow, etc;
+     who cares.  */
+
+  /* If this format uses a hidden bit, explicitly add it in now.  Otherwise,
+     increment the exponent by one to account for the integer bit.  */
+
+  if (!special_exponent)
+    {
+      if (fmt->intbit == floatformat_intbit_no)
+       mpfr_set_ui_2exp (to.val, 1, exponent, MPFR_RNDN);
+      else
+       exponent++;
+    }
+
+  gdb_mpfr tmp (to);
+
+  while (mant_bits_left > 0)
+    {
+      mant_bits = std::min (mant_bits_left, 32);
+
+      mant = get_field (from, order, fmt->totalsize, mant_off, mant_bits);
+
+      mpfr_set_si (tmp.val, mant, MPFR_RNDN);
+      mpfr_mul_2si (tmp.val, tmp.val, exponent - mant_bits, MPFR_RNDN);
+      mpfr_add (to.val, to.val, tmp.val, MPFR_RNDN);
+      exponent -= mant_bits;
+      mant_off += mant_bits;
+      mant_bits_left -= mant_bits;
+    }
+
+  /* Negate it if negative.  */
+  if (get_field (from, order, fmt->totalsize, fmt->sign_start, 1))
+    mpfr_neg (to.val, to.val, MPFR_RNDN);
+}
+
+void
+mpfr_float_ops::from_target (const struct type *type,
+                            const gdb_byte *from, gdb_mpfr &to) const
+{
+  from_target (floatformat_from_type (type), from, to);
+}
+
+void
+mpfr_float_ops::to_target (const struct floatformat *fmt,
+                          const gdb_mpfr &from, gdb_byte *orig_to) const
+{
+  unsigned char *to = orig_to;
+  mpfr_exp_t exponent;
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+  enum floatformat_byteorders order = fmt->byteorder;
+  unsigned char newto[FLOATFORMAT_LARGEST_BYTES];
+
+  if (order != floatformat_little)
+    order = floatformat_big;
+
+  if (order != fmt->byteorder)
+    to = newto;
+
+  memset (to, 0, floatformat_totalsize_bytes (fmt));
+
+  if (fmt->split_half)
+    {
+      gdb_mpfr top (from), bot (from);
+
+      mpfr_set (top.val, from.val, MPFR_RNDN);
+      /* If the rounded top half is Inf, the bottom must be 0 not NaN
+        or Inf.  */
+      if (mpfr_inf_p (top.val))
+       mpfr_set_zero (bot.val, 0);
+      else
+       mpfr_sub (bot.val, from.val, top.val, MPFR_RNDN);
+
+      to_target (fmt->split_half, top, to);
+      to_target (fmt->split_half, bot,
+                to + fmt->totalsize / FLOATFORMAT_CHAR_BIT / 2);
+      return;
+    }
+
+  gdb_mpfr tmp (from);
+
+  if (mpfr_zero_p (from.val))
+    goto finalize_byteorder;   /* Result is zero */
+
+  mpfr_set (tmp.val, from.val, MPFR_RNDN);
+
+  if (mpfr_nan_p (tmp.val))    /* Result is NaN */
+    {
+      /* From is NaN */
+      put_field (to, order, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, fmt->exp_nan);
+      /* Be sure it's not infinity, but NaN value is irrel.  */
+      put_field (to, order, fmt->totalsize, fmt->man_start,
+                fmt->man_len, 1);
+      goto finalize_byteorder;
+    }
+
+  /* If negative, set the sign bit.  */
+  if (mpfr_sgn (tmp.val) < 0)
+    {
+      put_field (to, order, fmt->totalsize, fmt->sign_start, 1, 1);
+      mpfr_neg (tmp.val, tmp.val, MPFR_RNDN);
+    }
+
+  if (mpfr_inf_p (tmp.val))            /* Result is Infinity.  */
+    {
+      /* Infinity exponent is same as NaN's.  */
+      put_field (to, order, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, fmt->exp_nan);
+      /* Infinity mantissa is all zeroes.  */
+      put_field (to, order, fmt->totalsize, fmt->man_start,
+                fmt->man_len, 0);
+      goto finalize_byteorder;
+    }
+
+  mpfr_frexp (&exponent, tmp.val, tmp.val, MPFR_RNDN);
+
+  if (exponent + fmt->exp_bias <= 0)
+    {
+      /* The value is too small to be expressed in the destination
+        type (not enough bits in the exponent.  Treat as 0.  */
+      put_field (to, order, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, 0);
+      put_field (to, order, fmt->totalsize, fmt->man_start,
+                fmt->man_len, 0);
+      goto finalize_byteorder;
+    }
+
+  if (exponent + fmt->exp_bias >= (1 << fmt->exp_len))
+    {
+      /* The value is too large to fit into the destination.
+        Treat as infinity.  */
+      put_field (to, order, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, fmt->exp_nan);
+      put_field (to, order, fmt->totalsize, fmt->man_start,
+                fmt->man_len, 0);
+      goto finalize_byteorder;
+    }
+
+  put_field (to, order, fmt->totalsize, fmt->exp_start, fmt->exp_len,
+            exponent + fmt->exp_bias - 1);
+
+  mant_bits_left = fmt->man_len;
+  mant_off = fmt->man_start;
+  while (mant_bits_left > 0)
+    {
+      unsigned long mant_long;
+
+      mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
+
+      mpfr_mul_2ui (tmp.val, tmp.val, 32, MPFR_RNDN);
+      mant_long = mpfr_get_ui (tmp.val, MPFR_RNDZ) & 0xffffffffL;
+      mpfr_sub_ui (tmp.val, tmp.val, mant_long, MPFR_RNDZ);
+
+      /* If the integer bit is implicit, then we need to discard it.
+         If we are discarding a zero, we should be (but are not) creating
+         a denormalized number which means adjusting the exponent
+         (I think).  */
+      if (mant_bits_left == fmt->man_len
+         && fmt->intbit == floatformat_intbit_no)
+       {
+         mant_long <<= 1;
+         mant_long &= 0xffffffffL;
+          /* If we are processing the top 32 mantissa bits of a doublest
+             so as to convert to a float value with implied integer bit,
+             we will only be putting 31 of those 32 bits into the
+             final value due to the discarding of the top bit.  In the
+             case of a small float value where the number of mantissa
+             bits is less than 32, discarding the top bit does not alter
+             the number of bits we will be adding to the result.  */
+          if (mant_bits == 32)
+            mant_bits -= 1;
+       }
+
+      if (mant_bits < 32)
+       {
+         /* The bits we want are in the most significant MANT_BITS bits of
+            mant_long.  Move them to the least significant.  */
+         mant_long >>= 32 - mant_bits;
+       }
+
+      put_field (to, order, fmt->totalsize,
+                mant_off, mant_bits, mant_long);
+      mant_off += mant_bits;
+      mant_bits_left -= mant_bits;
+    }
+
+ finalize_byteorder:
+  /* Do we need to byte-swap the words in the result?  */
+  if (order != fmt->byteorder)
+    floatformat_normalize_byteorder (fmt, newto, orig_to);
+}
+
+void
+mpfr_float_ops::to_target (const struct type *type,
+                          const gdb_mpfr &from, gdb_byte *to) const
+{
+  /* Ensure possible padding bytes in the target buffer are zeroed out.  */
+  memset (to, 0, TYPE_LENGTH (type));
+
+  to_target (floatformat_from_type (type), from, to);
+}
+
+/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
+   to a string, optionally using the print format FORMAT.  */
+std::string
+mpfr_float_ops::to_string (const gdb_byte *addr,
+                          const struct type *type,
+                          const char *format) const
+{
+  const struct floatformat *fmt = floatformat_from_type (type);
+
+  /* Unless we need to adhere to a specific format, provide special
+     output for certain cases.  */
+  if (format == nullptr)
+    {
+      /* Detect invalid representations.  */
+      if (!floatformat_is_valid (fmt, addr))
+       return "<invalid float value>";
+
+      /* Handle NaN and Inf.  */
+      enum float_kind kind = floatformat_classify (fmt, addr);
+      if (kind == float_nan)
+       {
+         const char *sign = floatformat_is_negative (fmt, addr)? "-" : "";
+         const char *mantissa = floatformat_mantissa (fmt, addr);
+         return string_printf ("%snan(0x%s)", sign, mantissa);
+       }
+      else if (kind == float_infinite)
+       {
+         const char *sign = floatformat_is_negative (fmt, addr)? "-" : "";
+         return string_printf ("%sinf", sign);
+       }
+    }
+
+  /* Determine the format string to use on the host side.  */
+  std::string host_format = floatformat_printf_format (fmt, format, 'R');
+
+  gdb_mpfr tmp (type);
+  from_target (type, addr, tmp);
+
+  int size = mpfr_snprintf (NULL, 0, host_format.c_str (), tmp.val);
+  std::string str (size, '\0');
+  mpfr_sprintf (&str[0], host_format.c_str (), tmp.val);
+
+  return str;
+}
+
+/* Parse string STRING into a target floating-number of type TYPE and
+   store it as byte-stream ADDR.  Return whether parsing succeeded.  */
+bool
+mpfr_float_ops::from_string (gdb_byte *addr,
+                            const struct type *type,
+                            const std::string &in) const
+{
+  gdb_mpfr tmp (type);
+
+  char *endptr;
+  mpfr_strtofr (tmp.val, in.c_str (), &endptr, 0, MPFR_RNDN);
+
+  /* We only accept the whole string.  */
+  if (*endptr)
+    return false;
+
+  to_target (type, tmp, addr);
+  return true;
+}
+
+/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
+   to an integer value (rounding towards zero).  */
+LONGEST
+mpfr_float_ops::to_longest (const gdb_byte *addr,
+                           const struct type *type) const
+{
+  gdb_mpfr tmp (type);
+  from_target (type, addr, tmp);
+  return mpfr_get_sj (tmp.val, MPFR_RNDZ);
+}
+
+/* Convert signed integer VAL to a target floating-number of type TYPE
+   and store it as byte-stream ADDR.  */
+void
+mpfr_float_ops::from_longest (gdb_byte *addr,
+                             const struct type *type,
+                             LONGEST val) const
+{
+  gdb_mpfr tmp (type);
+  mpfr_set_sj (tmp.val, val, MPFR_RNDN);
+  to_target (type, tmp, addr);
+}
+
+/* Convert unsigned integer VAL to a target floating-number of type TYPE
+   and store it as byte-stream ADDR.  */
+void
+mpfr_float_ops::from_ulongest (gdb_byte *addr,
+                              const struct type *type,
+                              ULONGEST val) const
+{
+  gdb_mpfr tmp (type);
+  mpfr_set_uj (tmp.val, val, MPFR_RNDN);
+  to_target (type, tmp, addr);
+}
+
+/* Convert the byte-stream ADDR, interpreted as floating-point type TYPE,
+   to a floating-point value in the host "double" format.  */
+double
+mpfr_float_ops::to_host_double (const gdb_byte *addr,
+                               const struct type *type) const
+{
+  gdb_mpfr tmp (type);
+  from_target (type, addr, tmp);
+  return mpfr_get_d (tmp.val, MPFR_RNDN);
+}
+
+/* Convert floating-point value VAL in the host "double" format to a target
+   floating-number of type TYPE and store it as byte-stream ADDR.  */
+void
+mpfr_float_ops::from_host_double (gdb_byte *addr,
+                                 const struct type *type,
+                                 double val) const
+{
+  gdb_mpfr tmp (type);
+  mpfr_set_d (tmp.val, val, MPFR_RNDN);
+  to_target (type, tmp, addr);
+}
+
+/* Convert a floating-point number of type FROM_TYPE from the target
+   byte-stream FROM to a floating-point number of type TO_TYPE, and
+   store it to the target byte-stream TO.  */
+void
+mpfr_float_ops::convert (const gdb_byte *from,
+                        const struct type *from_type,
+                        gdb_byte *to,
+                        const struct type *to_type) const
+{
+  gdb_mpfr from_tmp (from_type), to_tmp (to_type);
+  from_target (from_type, from, from_tmp);
+  mpfr_set (to_tmp.val, from_tmp.val, MPFR_RNDN);
+  to_target (to_type, to_tmp, to);
+}
+
+/* Perform the binary operation indicated by OPCODE, using as operands the
+   target byte streams X and Y, interpreted as floating-point numbers of
+   types TYPE_X and TYPE_Y, respectively.  Convert the result to type
+   TYPE_RES and store it into the byte-stream RES.  */
+void
+mpfr_float_ops::binop (enum exp_opcode op,
+                      const gdb_byte *x, const struct type *type_x,
+                      const gdb_byte *y, const struct type *type_y,
+                      gdb_byte *res, const struct type *type_res) const
+{
+  gdb_mpfr x_tmp (type_x), y_tmp (type_y), tmp (type_res);
+
+  from_target (type_x, x, x_tmp);
+  from_target (type_y, y, y_tmp);
+
+  switch (op)
+    {
+      case BINOP_ADD:
+       mpfr_add (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN);
+       break;
+
+      case BINOP_SUB:
+       mpfr_sub (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN);
+       break;
+
+      case BINOP_MUL:
+       mpfr_mul (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN);
+       break;
+
+      case BINOP_DIV:
+       mpfr_div (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN);
+       break;
+
+      case BINOP_EXP:
+       mpfr_pow (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN);
+       break;
+
+      case BINOP_MIN:
+       mpfr_min (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN);
+       break;
+
+      case BINOP_MAX:
+       mpfr_max (tmp.val, x_tmp.val, y_tmp.val, MPFR_RNDN);
+       break;
+
+      default:
+       error (_("Integer-only operation on floating point number."));
+       break;
+    }
+
+  to_target (type_res, tmp, res);
+}
+
+/* Compare the two target byte streams X and Y, interpreted as floating-point
+   numbers of types TYPE_X and TYPE_Y, respectively.  Return zero if X and Y
+   are equal, -1 if X is less than Y, and 1 otherwise.  */
+int
+mpfr_float_ops::compare (const gdb_byte *x, const struct type *type_x,
+                        const gdb_byte *y, const struct type *type_y) const
+{
+  gdb_mpfr x_tmp (type_x), y_tmp (type_y);
+
+  from_target (type_x, x, x_tmp);
+  from_target (type_y, y, y_tmp);
+
+  if (mpfr_equal_p (x_tmp.val, y_tmp.val))
+    return 0;
+  else if (mpfr_less_p (x_tmp.val, y_tmp.val))
+    return -1;
+  else
+    return 1;
+}
+
+#endif
+
+
 /* Helper routines operating on decimal floating-point data.  */
 
 /* Decimal floating point is one of the extension to IEEE 754, which is
@@ -1685,10 +2248,16 @@ get_target_float_ops (enum target_float_ops_kind kind)
        }
 
       /* For binary floating-point formats that do not match any host format,
+         use mpfr_t as intermediate format to provide precise target-floating
+         point emulation.  However, if the MPFR library is not availabe,
          use the largest host floating-point type as intermediate format.  */
       case target_float_ops_kind::binary:
         {
+#ifdef HAVE_LIBMPFR
+         static mpfr_float_ops binary_float_ops;
+#else
          static host_float_ops<long double> binary_float_ops;
+#endif
          return &binary_float_ops;
        }
 
index b916e93a92cdaed59f28a59c13d9814d80d1937a..00279828a0b8c84211ad4767af02d5d495b815b5 100644 (file)
@@ -1,3 +1,8 @@
+2017-11-22  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * gdb.base/float128.c (large128): New variable.
+       * gdb.base/float128.exp: Add test to print largest __float128 value.
+
 2017-11-22  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * gdb.arch/vsx-regs.exp: Update register content checks.
index 4ded2f4cc8cd745c506519847d544dc9800868fe..8cd437473b52cb1450029b277b83817662cf6f39 100644 (file)
 long double ld;
 __float128 f128;
 
+// Test largest IEEE-128 value.  This has to be supported since the
+// __float128 data type by definition is encoded as IEEE-128.
+__float128 large128 = 1.18973149535723176508575932662800702e+4932q;
+
 int main()
 {
   ld = 1.375l;
index 9a46282168a4d824b2e3011f58d55a434b3cc719..803bb5961144ed21be420533e916c025633eff9a 100644 (file)
@@ -74,3 +74,6 @@ gdb_test_multiple "set var f128=20.375l" "$test" {
 gdb_test "print ld" ".* = 10\\.375.*" "the value of ld is changed to 10.375"
 gdb_test "print f128" ".* = 20\\.375.*" "the value of f128 is changed to 20.375"
 
+# Test that we can correctly handle the largest IEEE-128 value
+gdb_test "print large128" ".* = 1\\.18973149535723176508575932662800702e\\+4932" "print large128"
+