/* Conversion routines from GCC internal float representation to MPFR. | |

Copyright (C) 2010-2018 Free Software Foundation, Inc. | |

This file is part of GCC. | |

GCC is free software; you can redistribute it and/or modify it under | |

the terms of the GNU General Public License as published by the Free | |

Software Foundation; either version 3, or (at your option) any later | |

version. | |

GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |

WARRANTY; without even the implied warranty of MERCHANTABILITY or | |

FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |

for more details. | |

You should have received a copy of the GNU General Public License | |

along with GCC; see the file COPYING3. If not see | |

<http://www.gnu.org/licenses/>. */ | |

#include "config.h" | |

#include "system.h" | |

#include "coretypes.h" | |

#include "tree.h" | |

#include "realmpfr.h" | |

#include "stor-layout.h" | |

/* Convert from REAL_VALUE_TYPE to MPFR. The caller is responsible | |

for initializing and clearing the MPFR parameter. */ | |

void | |

mpfr_from_real (mpfr_ptr m, const REAL_VALUE_TYPE *r, mp_rnd_t rndmode) | |

{ | |

/* We use a string as an intermediate type. */ | |

char buf[128]; | |

int ret; | |

/* Take care of Infinity and NaN. */ | |

if (r->cl == rvc_inf) | |

{ | |

mpfr_set_inf (m, r->sign == 1 ? -1 : 1); | |

return; | |

} | |

if (r->cl == rvc_nan) | |

{ | |

mpfr_set_nan (m); | |

return; | |

} | |

real_to_hexadecimal (buf, r, sizeof (buf), 0, 1); | |

/* mpfr_set_str() parses hexadecimal floats from strings in the same | |

format that GCC will output them. Nothing extra is needed. */ | |

ret = mpfr_set_str (m, buf, 16, rndmode); | |

gcc_assert (ret == 0); | |

} | |

/* Convert from MPFR to REAL_VALUE_TYPE, for a given format FORMAT and | |

rounding mode RNDMODE. FORMAT is only relevant if M is a NaN. */ | |

void | |

real_from_mpfr (REAL_VALUE_TYPE *r, mpfr_srcptr m, const real_format *format, | |

mp_rnd_t rndmode) | |

{ | |

/* We use a string as an intermediate type. */ | |

char buf[128], *rstr; | |

mp_exp_t exp; | |

/* Take care of Infinity and NaN. */ | |

if (mpfr_inf_p (m)) | |

{ | |

real_inf (r); | |

if (mpfr_sgn (m) < 0) | |

*r = real_value_negate (r); | |

return; | |

} | |

if (mpfr_nan_p (m)) | |

{ | |

real_nan (r, "", 1, format); | |

return; | |

} | |

rstr = mpfr_get_str (NULL, &exp, 16, 0, m, rndmode); | |

/* The additional 12 chars add space for the sprintf below. This | |

leaves 6 digits for the exponent which is supposedly enough. */ | |

gcc_assert (rstr != NULL && strlen (rstr) < sizeof (buf) - 12); | |

/* REAL_VALUE_ATOF expects the exponent for mantissa * 2**exp, | |

mpfr_get_str returns the exponent for mantissa * 16**exp, adjust | |

for that. */ | |

exp *= 4; | |

if (rstr[0] == '-') | |

sprintf (buf, "-0x.%sp%d", &rstr[1], (int) exp); | |

else | |

sprintf (buf, "0x.%sp%d", rstr, (int) exp); | |

mpfr_free_str (rstr); | |

real_from_string (r, buf); | |

} | |

/* Convert from MPFR to REAL_VALUE_TYPE, for a given type TYPE and rounding | |

mode RNDMODE. TYPE is only relevant if M is a NaN. */ | |

void | |

real_from_mpfr (REAL_VALUE_TYPE *r, mpfr_srcptr m, tree type, mp_rnd_t rndmode) | |

{ | |

real_from_mpfr (r, m, type ? REAL_MODE_FORMAT (TYPE_MODE (type)) : NULL, | |

rndmode); | |

} | |