Blame math/gen-auto-libm-tests.c

Packit 6c4009
/* Generate expected output for libm tests with MPFR and MPC.
Packit 6c4009
   Copyright (C) 2013-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* Compile this program as:
Packit 6c4009
Packit 6c4009
   gcc -std=gnu11 -O2 -Wall -Wextra gen-auto-libm-tests.c -lmpc -lmpfr -lgmp \
Packit 6c4009
     -o gen-auto-libm-tests
Packit 6c4009
Packit 6c4009
   (use of current MPC and MPFR versions recommended) and run it as:
Packit 6c4009
Packit 6c4009
   gen-auto-libm-tests auto-libm-test-in <func> auto-libm-test-out-<func>
Packit 6c4009
Packit 6c4009
   to generate results for normal libm functions, or
Packit 6c4009
Packit 6c4009
   gen-auto-libm-tests --narrow auto-libm-test-in <func> \
Packit 6c4009
     auto-libm-test-out-narrow-<func>
Packit 6c4009
Packit 6c4009
   to generate results for a function rounding results to a narrower
Packit 6c4009
   type (in the case of fma and sqrt, both output files are generated
Packit 6c4009
   from the same test inputs).
Packit 6c4009
Packit 6c4009
   The input file auto-libm-test-in contains three kinds of lines:
Packit 6c4009
Packit 6c4009
   Lines beginning with "#" are comments, and are ignored, as are
Packit 6c4009
   empty lines.
Packit 6c4009
Packit 6c4009
   Other lines are test lines, of the form "function input1 input2
Packit 6c4009
   ... [flag1 flag2 ...]".  Inputs are either finite real numbers or
Packit 6c4009
   integers, depending on the function under test.  Real numbers may
Packit 6c4009
   be in any form acceptable to mpfr_strtofr (base 0); integers in any
Packit 6c4009
   form acceptable to mpz_set_str (base 0).  In addition, real numbers
Packit 6c4009
   may be certain special strings such as "pi", as listed in the
Packit 6c4009
   special_real_inputs array.
Packit 6c4009
Packit 6c4009
   Each flag is a flag name possibly followed by a series of
Packit 6c4009
   ":condition".  Conditions may be any of the names of floating-point
Packit 6c4009
   formats in the floating_point_formats array, "long32" and "long64"
Packit 6c4009
   to indicate the number of bits in the "long" type, or other strings
Packit 6c4009
   for which libm-test.inc defines a TEST_COND_<condition> macro (with
Packit 6c4009
   "-"- changed to "_" in the condition name) evaluating to nonzero
Packit 6c4009
   when the condition is true and zero when the condition is false.
Packit 6c4009
   The meaning is that the flag applies to the test if all the listed
Packit 6c4009
   conditions are true.  "flag:cond1:cond2 flag:cond3:cond4" means the
Packit 6c4009
   flag applies if ((cond1 && cond2) || (cond3 && cond4)).
Packit 6c4009
Packit 6c4009
   A real number specified as an input is considered to represent the
Packit 6c4009
   set of real numbers arising from rounding the given number in any
Packit 6c4009
   direction for any supported floating-point format; any roundings
Packit 6c4009
   that give infinity are ignored.  Each input on a test line has all
Packit 6c4009
   the possible roundings considered independently.  Each resulting
Packit 6c4009
   choice of the tuple of inputs to the function is ignored if the
Packit 6c4009
   mathematical result of the function involves a NaN or an exact
Packit 6c4009
   infinity, and is otherwise considered for each floating-point
Packit 6c4009
   format for which all those inputs are exactly representable.  Thus
Packit 6c4009
   tests may result in "overflow", "underflow" and "inexact"
Packit 6c4009
   exceptions; "invalid" may arise only when the final result type is
Packit 6c4009
   an integer type and it is the conversion of a mathematically
Packit 6c4009
   defined finite result to integer type that results in that
Packit 6c4009
   exception.
Packit 6c4009
Packit 6c4009
   By default, it is assumed that "overflow" and "underflow"
Packit 6c4009
   exceptions should be correct, but that "inexact" exceptions should
Packit 6c4009
   only be correct for functions listed as exactly determined.  For
Packit 6c4009
   such functions, "underflow" exceptions should respect whether the
Packit 6c4009
   machine has before-rounding or after-rounding tininess detection.
Packit 6c4009
   For other functions, it is considered that if the exact result is
Packit 6c4009
   somewhere between the greatest magnitude subnormal of a given sign
Packit 6c4009
   (exclusive) and the least magnitude normal of that sign
Packit 6c4009
   (inclusive), underflow exceptions are permitted but optional on all
Packit 6c4009
   machines, and they are also permitted but optional for smaller
Packit 6c4009
   subnormal exact results for functions that are not exactly
Packit 6c4009
   determined.  errno setting is expected for overflow to infinity and
Packit 6c4009
   underflow to zero (for real functions), and for out-of-range
Packit 6c4009
   conversion of a finite result to integer type, and is considered
Packit 6c4009
   permitted but optional for all other cases where overflow
Packit 6c4009
   exceptions occur, and where underflow exceptions occur or are
Packit 6c4009
   permitted.  In other cases (where no overflow or underflow is
Packit 6c4009
   permitted), errno is expected to be left unchanged.
Packit 6c4009
Packit 6c4009
   The flag "no-test-inline" indicates a test is disabled for inline
Packit 6c4009
   function testing; "ignore-zero-inf-sign" indicates the the signs of
Packit 6c4009
   zero and infinite results should be ignored; "xfail" indicates the
Packit 6c4009
   test is disabled as expected to produce incorrect results,
Packit 6c4009
   "xfail-rounding" indicates the test is disabled only in rounding
Packit 6c4009
   modes other than round-to-nearest.  Otherwise, test flags are of
Packit 6c4009
   the form "spurious-<exception>" and "missing-<exception>", for any
Packit 6c4009
   exception ("overflow", "underflow", "inexact", "invalid",
Packit 6c4009
   "divbyzero"), "spurious-errno" and "missing-errno", to indicate
Packit 6c4009
   when tests are expected to deviate from the exception and errno
Packit 6c4009
   settings corresponding to the mathematical results.  "xfail",
Packit 6c4009
   "xfail-rounding", "spurious-" and "missing-" flags should be
Packit 6c4009
   accompanied by a comment referring to an open bug in glibc
Packit 6c4009
   Bugzilla.
Packit 6c4009
Packit 6c4009
   The output file auto-libm-test-out-<func> contains the test lines from
Packit 6c4009
   auto-libm-test-in, and, after the line for a given test, some
Packit 6c4009
   number of output test lines.  An output test line is of the form "=
Packit 6c4009
   function rounding-mode format input1 input2 ... : output1 output2
Packit 6c4009
   ... : flags".  rounding-mode is "tonearest", "towardzero", "upward"
Packit 6c4009
   or "downward".  format is a name from the floating_point_formats
Packit 6c4009
   array, possibly followed by a sequence of ":flag" for flags from
Packit 6c4009
   "long32" and "long64".  Inputs and outputs are specified as hex
Packit 6c4009
   floats with the required suffix for the floating-point type, or
Packit 6c4009
   plus_infty or minus_infty for infinite expected results, or as
Packit 6c4009
   integer constant expressions (not necessarily with the right type)
Packit 6c4009
   or IGNORE for integer inputs and outputs.  Flags are
Packit 6c4009
   "no-test-inline", "ignore-zero-info-sign", "xfail", "<exception>",
Packit 6c4009
   "<exception>-ok", "errno-<value>", "errno-<value>-ok", which may be
Packit 6c4009
   unconditional or conditional.  "<exception>" indicates that a
Packit 6c4009
   correct result means the given exception should be raised.
Packit 6c4009
   "errno-<value>" indicates that a correct result means errno should
Packit 6c4009
   be set to the given value.  "-ok" means not to test for the given
Packit 6c4009
   exception or errno value (whether because it was marked as possibly
Packit 6c4009
   missing or spurious, or because the calculation of correct results
Packit 6c4009
   indicated it was optional).  Conditions "before-rounding" and
Packit 6c4009
   "after-rounding" indicate tests where expectations for underflow
Packit 6c4009
   exceptions depend on how the architecture detects tininess.
Packit 6c4009
Packit 6c4009
   For functions rounding their results to a narrower type, the format
Packit 6c4009
   given on an output test line is the result format followed by
Packit 6c4009
   information about the requirements on the argument format to be
Packit 6c4009
   able to represent the argument values, in the form
Packit 6c4009
   "format:arg_fmt(MAX_EXP,NUM_ONES,MIN_EXP,MAX_PREC)".  Instead of
Packit 6c4009
   separate lines for separate argument formats, an output test line
Packit 6c4009
   relates to all argument formats that can represent the values.
Packit 6c4009
   MAX_EXP is the maximum exponent of a nonzero bit in any argument,
Packit 6c4009
   or 0 if all arguments are zero; NUM_ONES is the maximum number of
Packit 6c4009
   leading bits with value 1 in an argument with exponent MAX_EXP, or
Packit 6c4009
   0 if all arguments are zero; MIN_EXP is the minimum exponent of a
Packit 6c4009
   nonzero bit in any argument, or 0 if all arguments are zero;
Packit 6c4009
   MAX_PREC is the maximum precision required to represent all
Packit 6c4009
   arguments, or 0 if all arguments are zero.  */
Packit 6c4009
Packit 6c4009
#define _GNU_SOURCE
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <error.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
#include <gmp.h>
Packit 6c4009
#include <mpfr.h>
Packit 6c4009
#include <mpc.h>
Packit 6c4009
Packit 6c4009
#define ARRAY_SIZE(A) (sizeof (A) / sizeof ((A)[0]))
Packit 6c4009
Packit 6c4009
/* The supported floating-point formats.  */
Packit 6c4009
typedef enum
Packit 6c4009
  {
Packit 6c4009
    fp_flt_32,
Packit 6c4009
    fp_dbl_64,
Packit 6c4009
    fp_ldbl_96_intel,
Packit 6c4009
    fp_ldbl_96_m68k,
Packit 6c4009
    fp_ldbl_128,
Packit 6c4009
    fp_ldbl_128ibm,
Packit 6c4009
    fp_num_formats,
Packit 6c4009
    fp_first_format = 0
Packit 6c4009
  } fp_format;
Packit 6c4009
Packit 6c4009
/* Structure describing a single floating-point format.  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  /* The name of the format.  */
Packit 6c4009
  const char *name;
Packit 6c4009
  /* A string for the largest normal value, or NULL for IEEE formats
Packit 6c4009
     where this can be determined automatically.  */
Packit 6c4009
  const char *max_string;
Packit 6c4009
  /* The number of mantissa bits.  */
Packit 6c4009
  int mant_dig;
Packit 6c4009
  /* The least N such that 2^N overflows.  */
Packit 6c4009
  int max_exp;
Packit 6c4009
  /* One more than the least N such that 2^N is normal.  */
Packit 6c4009
  int min_exp;
Packit 6c4009
  /* The largest normal value.  */
Packit 6c4009
  mpfr_t max;
Packit 6c4009
  /* The value 0.5ulp above the least positive normal value.  */
Packit 6c4009
  mpfr_t min_plus_half;
Packit 6c4009
  /* The least positive normal value, 2^(MIN_EXP-1).  */
Packit 6c4009
  mpfr_t min;
Packit 6c4009
  /* The greatest positive subnormal value.  */
Packit 6c4009
  mpfr_t subnorm_max;
Packit 6c4009
  /* The least positive subnormal value, 2^(MIN_EXP-MANT_DIG).  */
Packit 6c4009
  mpfr_t subnorm_min;
Packit 6c4009
} fp_format_desc;
Packit 6c4009
Packit 6c4009
/* List of floating-point formats, in the same order as the fp_format
Packit 6c4009
   enumeration.  */
Packit 6c4009
static fp_format_desc fp_formats[fp_num_formats] =
Packit 6c4009
  {
Packit 6c4009
    { "binary32", NULL, 24, 128, -125, {}, {}, {}, {}, {} },
Packit 6c4009
    { "binary64", NULL, 53, 1024, -1021, {}, {}, {}, {}, {} },
Packit 6c4009
    { "intel96", NULL, 64, 16384, -16381, {}, {}, {}, {}, {} },
Packit 6c4009
    { "m68k96", NULL, 64, 16384, -16382, {}, {}, {}, {}, {} },
Packit 6c4009
    { "binary128", NULL, 113, 16384, -16381, {}, {}, {}, {}, {} },
Packit 6c4009
    { "ibm128", "0x1.fffffffffffff7ffffffffffff8p+1023",
Packit 6c4009
      106, 1024, -968, {}, {}, {}, {}, {} },
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* The supported rounding modes.  */
Packit 6c4009
typedef enum
Packit 6c4009
  {
Packit 6c4009
    rm_downward,
Packit 6c4009
    rm_tonearest,
Packit 6c4009
    rm_towardzero,
Packit 6c4009
    rm_upward,
Packit 6c4009
    rm_num_modes,
Packit 6c4009
    rm_first_mode = 0
Packit 6c4009
  } rounding_mode;
Packit 6c4009
Packit 6c4009
/* Structure describing a single rounding mode.  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  /* The name of the rounding mode.  */
Packit 6c4009
  const char *name;
Packit 6c4009
  /* The MPFR rounding mode.  */
Packit 6c4009
  mpfr_rnd_t mpfr_mode;
Packit 6c4009
  /* The MPC rounding mode.  */
Packit 6c4009
  mpc_rnd_t mpc_mode;
Packit 6c4009
} rounding_mode_desc;
Packit 6c4009
Packit 6c4009
/* List of rounding modes, in the same order as the rounding_mode
Packit 6c4009
   enumeration.  */
Packit 6c4009
static const rounding_mode_desc rounding_modes[rm_num_modes] =
Packit 6c4009
  {
Packit 6c4009
    { "downward", MPFR_RNDD, MPC_RNDDD },
Packit 6c4009
    { "tonearest", MPFR_RNDN, MPC_RNDNN },
Packit 6c4009
    { "towardzero", MPFR_RNDZ, MPC_RNDZZ },
Packit 6c4009
    { "upward", MPFR_RNDU, MPC_RNDUU },
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* The supported exceptions.  */
Packit 6c4009
typedef enum
Packit 6c4009
  {
Packit 6c4009
    exc_divbyzero,
Packit 6c4009
    exc_inexact,
Packit 6c4009
    exc_invalid,
Packit 6c4009
    exc_overflow,
Packit 6c4009
    exc_underflow,
Packit 6c4009
    exc_num_exceptions,
Packit 6c4009
    exc_first_exception = 0
Packit 6c4009
  } fp_exception;
Packit 6c4009
Packit 6c4009
/* List of exceptions, in the same order as the fp_exception
Packit 6c4009
   enumeration.  */
Packit 6c4009
static const char *const exceptions[exc_num_exceptions] =
Packit 6c4009
  {
Packit 6c4009
    "divbyzero",
Packit 6c4009
    "inexact",
Packit 6c4009
    "invalid",
Packit 6c4009
    "overflow",
Packit 6c4009
    "underflow",
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* The internal precision to use for most MPFR calculations, which
Packit 6c4009
   must be at least 2 more than the greatest precision of any
Packit 6c4009
   supported floating-point format.  */
Packit 6c4009
static int internal_precision;
Packit 6c4009
Packit 6c4009
/* A value that overflows all supported floating-point formats.  */
Packit 6c4009
static mpfr_t global_max;
Packit 6c4009
Packit 6c4009
/* A value that is at most half the least subnormal in any
Packit 6c4009
   floating-point format and so is rounded the same way as all
Packit 6c4009
   sufficiently small positive values.  */
Packit 6c4009
static mpfr_t global_min;
Packit 6c4009
Packit 6c4009
/* The maximum number of (real or integer) arguments to a function
Packit 6c4009
   handled by this program (complex arguments count as two real
Packit 6c4009
   arguments).  */
Packit 6c4009
#define MAX_NARGS 4
Packit 6c4009
Packit 6c4009
/* The maximum number of (real or integer) return values from a
Packit 6c4009
   function handled by this program.  */
Packit 6c4009
#define MAX_NRET 2
Packit 6c4009
Packit 6c4009
/* A type of a function argument or return value.  */
Packit 6c4009
typedef enum
Packit 6c4009
  {
Packit 6c4009
    /* No type (not a valid argument or return value).  */
Packit 6c4009
    type_none,
Packit 6c4009
    /* A floating-point value with the type corresponding to that of
Packit 6c4009
       the function.  */
Packit 6c4009
    type_fp,
Packit 6c4009
    /* An integer value of type int.  */
Packit 6c4009
    type_int,
Packit 6c4009
    /* An integer value of type long.  */
Packit 6c4009
    type_long,
Packit 6c4009
    /* An integer value of type long long.  */
Packit 6c4009
    type_long_long,
Packit 6c4009
  } arg_ret_type;
Packit 6c4009
Packit 6c4009
/* A type of a generic real or integer value.  */
Packit 6c4009
typedef enum
Packit 6c4009
  {
Packit 6c4009
    /* No type.  */
Packit 6c4009
    gtype_none,
Packit 6c4009
    /* Floating-point (represented with MPFR).  */
Packit 6c4009
    gtype_fp,
Packit 6c4009
    /* Integer (represented with GMP).  */
Packit 6c4009
    gtype_int,
Packit 6c4009
  } generic_value_type;
Packit 6c4009
Packit 6c4009
/* A generic value (argument or result).  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  /* The type of this value.  */
Packit 6c4009
  generic_value_type type;
Packit 6c4009
  /* Its value.  */
Packit 6c4009
  union
Packit 6c4009
  {
Packit 6c4009
    mpfr_t f;
Packit 6c4009
    mpz_t i;
Packit 6c4009
  } value;
Packit 6c4009
} generic_value;
Packit 6c4009
Packit 6c4009
/* A type of input flag.  */
Packit 6c4009
typedef enum
Packit 6c4009
  {
Packit 6c4009
    flag_no_test_inline,
Packit 6c4009
    flag_ignore_zero_inf_sign,
Packit 6c4009
    flag_xfail,
Packit 6c4009
    flag_xfail_rounding,
Packit 6c4009
    /* The "spurious" and "missing" flags must be in the same order as
Packit 6c4009
       the fp_exception enumeration.  */
Packit 6c4009
    flag_spurious_divbyzero,
Packit 6c4009
    flag_spurious_inexact,
Packit 6c4009
    flag_spurious_invalid,
Packit 6c4009
    flag_spurious_overflow,
Packit 6c4009
    flag_spurious_underflow,
Packit 6c4009
    flag_spurious_errno,
Packit 6c4009
    flag_missing_divbyzero,
Packit 6c4009
    flag_missing_inexact,
Packit 6c4009
    flag_missing_invalid,
Packit 6c4009
    flag_missing_overflow,
Packit 6c4009
    flag_missing_underflow,
Packit 6c4009
    flag_missing_errno,
Packit 6c4009
    num_input_flag_types,
Packit 6c4009
    flag_first_flag = 0,
Packit 6c4009
    flag_spurious_first = flag_spurious_divbyzero,
Packit 6c4009
    flag_missing_first = flag_missing_divbyzero
Packit 6c4009
  } input_flag_type;
Packit 6c4009
Packit 6c4009
/* List of flags, in the same order as the input_flag_type
Packit 6c4009
   enumeration.  */
Packit 6c4009
static const char *const input_flags[num_input_flag_types] =
Packit 6c4009
  {
Packit 6c4009
    "no-test-inline",
Packit 6c4009
    "ignore-zero-inf-sign",
Packit 6c4009
    "xfail",
Packit 6c4009
    "xfail-rounding",
Packit 6c4009
    "spurious-divbyzero",
Packit 6c4009
    "spurious-inexact",
Packit 6c4009
    "spurious-invalid",
Packit 6c4009
    "spurious-overflow",
Packit 6c4009
    "spurious-underflow",
Packit 6c4009
    "spurious-errno",
Packit 6c4009
    "missing-divbyzero",
Packit 6c4009
    "missing-inexact",
Packit 6c4009
    "missing-invalid",
Packit 6c4009
    "missing-overflow",
Packit 6c4009
    "missing-underflow",
Packit 6c4009
    "missing-errno",
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* An input flag, possibly conditional.  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  /* The type of this flag.  */
Packit 6c4009
  input_flag_type type;
Packit 6c4009
  /* The conditions on this flag, as a string ":cond1:cond2..." or
Packit 6c4009
     NULL.  */
Packit 6c4009
  const char *cond;
Packit 6c4009
} input_flag;
Packit 6c4009
Packit 6c4009
/* Structure describing a single test from the input file (which may
Packit 6c4009
   expand into many tests in the output).  The choice of function,
Packit 6c4009
   which implies the numbers and types of arguments and results, is
Packit 6c4009
   implicit rather than stored in this structure (except as part of
Packit 6c4009
   the source line).  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  /* The text of the input line describing the test, including the
Packit 6c4009
     trailing newline.  */
Packit 6c4009
  const char *line;
Packit 6c4009
  /* The number of combinations of interpretations of input values for
Packit 6c4009
     different floating-point formats and rounding modes.  */
Packit 6c4009
  size_t num_input_cases;
Packit 6c4009
  /* The corresponding lists of inputs.  */
Packit 6c4009
  generic_value **inputs;
Packit 6c4009
  /* The number of flags for this test.  */
Packit 6c4009
  size_t num_flags;
Packit 6c4009
  /* The corresponding list of flags.  */
Packit 6c4009
  input_flag *flags;
Packit 6c4009
  /* The old output for this test.  */
Packit 6c4009
  const char *old_output;
Packit 6c4009
} input_test;
Packit 6c4009
Packit 6c4009
/* Ways to calculate a function.  */
Packit 6c4009
typedef enum
Packit 6c4009
  {
Packit 6c4009
    /* MPFR function with a single argument and result.  */
Packit 6c4009
    mpfr_f_f,
Packit 6c4009
    /* MPFR function with two arguments and one result.  */
Packit 6c4009
    mpfr_ff_f,
Packit 6c4009
    /* MPFR function with three arguments and one result.  */
Packit 6c4009
    mpfr_fff_f,
Packit 6c4009
    /* MPFR function with a single argument and floating-point and
Packit 6c4009
       integer results.  */
Packit 6c4009
    mpfr_f_f1,
Packit 6c4009
    /* MPFR function with integer and floating-point arguments and one
Packit 6c4009
       result.  */
Packit 6c4009
    mpfr_if_f,
Packit 6c4009
    /* MPFR function with a single argument and two floating-point
Packit 6c4009
       results.  */
Packit 6c4009
    mpfr_f_11,
Packit 6c4009
    /* MPC function with a single complex argument and one real
Packit 6c4009
       result.  */
Packit 6c4009
    mpc_c_f,
Packit 6c4009
    /* MPC function with a single complex argument and one complex
Packit 6c4009
       result.  */
Packit 6c4009
    mpc_c_c,
Packit 6c4009
    /* MPC function with two complex arguments and one complex
Packit 6c4009
       result.  */
Packit 6c4009
    mpc_cc_c,
Packit 6c4009
  } func_calc_method;
Packit 6c4009
Packit 6c4009
/* Description of how to calculate a function.  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  /* Which method is used to calculate the function.  */
Packit 6c4009
  func_calc_method method;
Packit 6c4009
  /* The specific function called.  */
Packit 6c4009
  union
Packit 6c4009
  {
Packit 6c4009
    int (*mpfr_f_f) (mpfr_t, const mpfr_t, mpfr_rnd_t);
Packit 6c4009
    int (*mpfr_ff_f) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t);
Packit 6c4009
    int (*mpfr_fff_f) (mpfr_t, const mpfr_t, const mpfr_t, const mpfr_t,
Packit 6c4009
		       mpfr_rnd_t);
Packit 6c4009
    int (*mpfr_f_f1) (mpfr_t, int *, const mpfr_t, mpfr_rnd_t);
Packit 6c4009
    int (*mpfr_if_f) (mpfr_t, long, const mpfr_t, mpfr_rnd_t);
Packit 6c4009
    int (*mpfr_f_11) (mpfr_t, mpfr_t, const mpfr_t, mpfr_rnd_t);
Packit 6c4009
    int (*mpc_c_f) (mpfr_t, const mpc_t, mpfr_rnd_t);
Packit 6c4009
    int (*mpc_c_c) (mpc_t, const mpc_t, mpc_rnd_t);
Packit 6c4009
    int (*mpc_cc_c) (mpc_t, const mpc_t, const mpc_t, mpc_rnd_t);
Packit 6c4009
  } func;
Packit 6c4009
} func_calc_desc;
Packit 6c4009
Packit 6c4009
/* Structure describing a function handled by this program.  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  /* The name of the function.  */
Packit 6c4009
  const char *name;
Packit 6c4009
  /* The number of arguments.  */
Packit 6c4009
  size_t num_args;
Packit 6c4009
  /* The types of the arguments.  */
Packit 6c4009
  arg_ret_type arg_types[MAX_NARGS];
Packit 6c4009
  /* The number of return values.  */
Packit 6c4009
  size_t num_ret;
Packit 6c4009
  /* The types of the return values.  */
Packit 6c4009
  arg_ret_type ret_types[MAX_NRET];
Packit 6c4009
  /* Whether the function has exactly determined results and
Packit 6c4009
     exceptions.  */
Packit 6c4009
  bool exact;
Packit 6c4009
  /* Whether the function is a complex function, so errno setting is
Packit 6c4009
     optional.  */
Packit 6c4009
  bool complex_fn;
Packit 6c4009
  /* Whether to treat arguments given as floating-point constants as
Packit 6c4009
     exact only, rather than rounding them up and down to all
Packit 6c4009
     formats.  */
Packit 6c4009
  bool exact_args;
Packit 6c4009
  /* How to calculate this function.  */
Packit 6c4009
  func_calc_desc calc;
Packit 6c4009
  /* The number of tests allocated for this function.  */
Packit 6c4009
  size_t num_tests_alloc;
Packit 6c4009
  /* The number of tests for this function.  */
Packit 6c4009
  size_t num_tests;
Packit 6c4009
  /* The tests themselves.  */
Packit 6c4009
  input_test *tests;
Packit 6c4009
} test_function;
Packit 6c4009
Packit 6c4009
#define ARGS1(T1) 1, { T1 }
Packit 6c4009
#define ARGS2(T1, T2) 2, { T1, T2 }
Packit 6c4009
#define ARGS3(T1, T2, T3) 3, { T1, T2, T3 }
Packit 6c4009
#define ARGS4(T1, T2, T3, T4) 4, { T1, T2, T3, T4 }
Packit 6c4009
#define RET1(T1) 1, { T1 }
Packit 6c4009
#define RET2(T1, T2) 2, { T1, T2 }
Packit 6c4009
#define CALC(TYPE, FN) { TYPE, { .TYPE = FN } }
Packit 6c4009
#define FUNC(NAME, ARGS, RET, EXACT, COMPLEX_FN, EXACT_ARGS, CALC)	\
Packit 6c4009
  {									\
Packit 6c4009
    NAME, ARGS, RET, EXACT, COMPLEX_FN, EXACT_ARGS, CALC, 0, 0, NULL	\
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
#define FUNC_mpfr_f_f(NAME, MPFR_FUNC, EXACT)				\
Packit 6c4009
  FUNC (NAME, ARGS1 (type_fp), RET1 (type_fp), EXACT, false, false,	\
Packit 6c4009
	CALC (mpfr_f_f, MPFR_FUNC))
Packit 6c4009
#define FUNC_mpfr_ff_f(NAME, MPFR_FUNC, EXACT)				\
Packit 6c4009
  FUNC (NAME, ARGS2 (type_fp, type_fp), RET1 (type_fp), EXACT, false,	\
Packit 6c4009
	false, CALC (mpfr_ff_f, MPFR_FUNC))
Packit 6c4009
#define FUNC_mpfr_if_f(NAME, MPFR_FUNC, EXACT)				\
Packit 6c4009
  FUNC (NAME, ARGS2 (type_int, type_fp), RET1 (type_fp), EXACT, false,	\
Packit 6c4009
	false, CALC (mpfr_if_f, MPFR_FUNC))
Packit 6c4009
#define FUNC_mpc_c_f(NAME, MPFR_FUNC, EXACT)				\
Packit 6c4009
  FUNC (NAME, ARGS2 (type_fp, type_fp), RET1 (type_fp), EXACT, true,	\
Packit 6c4009
	false, CALC (mpc_c_f, MPFR_FUNC))
Packit 6c4009
#define FUNC_mpc_c_c(NAME, MPFR_FUNC, EXACT)				\
Packit 6c4009
  FUNC (NAME, ARGS2 (type_fp, type_fp), RET2 (type_fp, type_fp), EXACT, \
Packit 6c4009
	true, false, CALC (mpc_c_c, MPFR_FUNC))
Packit 6c4009
Packit 6c4009
/* List of functions handled by this program.  */
Packit 6c4009
static test_function test_functions[] =
Packit 6c4009
  {
Packit 6c4009
    FUNC_mpfr_f_f ("acos", mpfr_acos, false),
Packit 6c4009
    FUNC_mpfr_f_f ("acosh", mpfr_acosh, false),
Packit 6c4009
    FUNC_mpfr_ff_f ("add", mpfr_add, true),
Packit 6c4009
    FUNC_mpfr_f_f ("asin", mpfr_asin, false),
Packit 6c4009
    FUNC_mpfr_f_f ("asinh", mpfr_asinh, false),
Packit 6c4009
    FUNC_mpfr_f_f ("atan", mpfr_atan, false),
Packit 6c4009
    FUNC_mpfr_ff_f ("atan2", mpfr_atan2, false),
Packit 6c4009
    FUNC_mpfr_f_f ("atanh", mpfr_atanh, false),
Packit 6c4009
    FUNC_mpc_c_f ("cabs", mpc_abs, false),
Packit 6c4009
    FUNC_mpc_c_c ("cacos", mpc_acos, false),
Packit 6c4009
    FUNC_mpc_c_c ("cacosh", mpc_acosh, false),
Packit 6c4009
    FUNC_mpc_c_f ("carg", mpc_arg, false),
Packit 6c4009
    FUNC_mpc_c_c ("casin", mpc_asin, false),
Packit 6c4009
    FUNC_mpc_c_c ("casinh", mpc_asinh, false),
Packit 6c4009
    FUNC_mpc_c_c ("catan", mpc_atan, false),
Packit 6c4009
    FUNC_mpc_c_c ("catanh", mpc_atanh, false),
Packit 6c4009
    FUNC_mpfr_f_f ("cbrt", mpfr_cbrt, false),
Packit 6c4009
    FUNC_mpc_c_c ("ccos", mpc_cos, false),
Packit 6c4009
    FUNC_mpc_c_c ("ccosh", mpc_cosh, false),
Packit 6c4009
    FUNC_mpc_c_c ("cexp", mpc_exp, false),
Packit 6c4009
    FUNC_mpc_c_c ("clog", mpc_log, false),
Packit 6c4009
    FUNC_mpc_c_c ("clog10", mpc_log10, false),
Packit 6c4009
    FUNC_mpfr_f_f ("cos", mpfr_cos, false),
Packit 6c4009
    FUNC_mpfr_f_f ("cosh", mpfr_cosh, false),
Packit 6c4009
    FUNC ("cpow", ARGS4 (type_fp, type_fp, type_fp, type_fp),
Packit 6c4009
	  RET2 (type_fp, type_fp), false, true, false,
Packit 6c4009
	  CALC (mpc_cc_c, mpc_pow)),
Packit 6c4009
    FUNC_mpc_c_c ("csin", mpc_sin, false),
Packit 6c4009
    FUNC_mpc_c_c ("csinh", mpc_sinh, false),
Packit 6c4009
    FUNC_mpc_c_c ("csqrt", mpc_sqrt, false),
Packit 6c4009
    FUNC_mpc_c_c ("ctan", mpc_tan, false),
Packit 6c4009
    FUNC_mpc_c_c ("ctanh", mpc_tanh, false),
Packit 6c4009
    FUNC_mpfr_ff_f ("div", mpfr_div, true),
Packit 6c4009
    FUNC_mpfr_f_f ("erf", mpfr_erf, false),
Packit 6c4009
    FUNC_mpfr_f_f ("erfc", mpfr_erfc, false),
Packit 6c4009
    FUNC_mpfr_f_f ("exp", mpfr_exp, false),
Packit 6c4009
    FUNC_mpfr_f_f ("exp10", mpfr_exp10, false),
Packit 6c4009
    FUNC_mpfr_f_f ("exp2", mpfr_exp2, false),
Packit 6c4009
    FUNC_mpfr_f_f ("expm1", mpfr_expm1, false),
Packit 6c4009
    FUNC ("fma", ARGS3 (type_fp, type_fp, type_fp), RET1 (type_fp),
Packit 6c4009
	  true, false, true, CALC (mpfr_fff_f, mpfr_fma)),
Packit 6c4009
    FUNC_mpfr_ff_f ("hypot", mpfr_hypot, false),
Packit 6c4009
    FUNC_mpfr_f_f ("j0", mpfr_j0, false),
Packit 6c4009
    FUNC_mpfr_f_f ("j1", mpfr_j1, false),
Packit 6c4009
    FUNC_mpfr_if_f ("jn", mpfr_jn, false),
Packit 6c4009
    FUNC ("lgamma", ARGS1 (type_fp), RET2 (type_fp, type_int), false, false,
Packit 6c4009
	  false, CALC (mpfr_f_f1, mpfr_lgamma)),
Packit 6c4009
    FUNC_mpfr_f_f ("log", mpfr_log, false),
Packit 6c4009
    FUNC_mpfr_f_f ("log10", mpfr_log10, false),
Packit 6c4009
    FUNC_mpfr_f_f ("log1p", mpfr_log1p, false),
Packit 6c4009
    FUNC_mpfr_f_f ("log2", mpfr_log2, false),
Packit 6c4009
    FUNC_mpfr_ff_f ("mul", mpfr_mul, true),
Packit 6c4009
    FUNC_mpfr_ff_f ("pow", mpfr_pow, false),
Packit 6c4009
    FUNC_mpfr_f_f ("sin", mpfr_sin, false),
Packit 6c4009
    FUNC ("sincos", ARGS1 (type_fp), RET2 (type_fp, type_fp), false, false,
Packit 6c4009
	  false, CALC (mpfr_f_11, mpfr_sin_cos)),
Packit 6c4009
    FUNC_mpfr_f_f ("sinh", mpfr_sinh, false),
Packit 6c4009
    FUNC_mpfr_ff_f ("sub", mpfr_sub, true),
Packit 6c4009
    FUNC_mpfr_f_f ("sqrt", mpfr_sqrt, true),
Packit 6c4009
    FUNC_mpfr_f_f ("tan", mpfr_tan, false),
Packit 6c4009
    FUNC_mpfr_f_f ("tanh", mpfr_tanh, false),
Packit 6c4009
    FUNC_mpfr_f_f ("tgamma", mpfr_gamma, false),
Packit 6c4009
    FUNC_mpfr_f_f ("y0", mpfr_y0, false),
Packit 6c4009
    FUNC_mpfr_f_f ("y1", mpfr_y1, false),
Packit 6c4009
    FUNC_mpfr_if_f ("yn", mpfr_yn, false),
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* Allocate memory, with error checking.  */
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
xmalloc (size_t n)
Packit 6c4009
{
Packit 6c4009
  void *p = malloc (n);
Packit 6c4009
  if (p == NULL)
Packit 6c4009
    error (EXIT_FAILURE, errno, "xmalloc failed");
Packit 6c4009
  return p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
xrealloc (void *p, size_t n)
Packit 6c4009
{
Packit 6c4009
  p = realloc (p, n);
Packit 6c4009
  if (p == NULL)
Packit 6c4009
    error (EXIT_FAILURE, errno, "xrealloc failed");
Packit 6c4009
  return p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static char *
Packit 6c4009
xstrdup (const char *s)
Packit 6c4009
{
Packit 6c4009
  char *p = strdup (s);
Packit 6c4009
  if (p == NULL)
Packit 6c4009
    error (EXIT_FAILURE, errno, "xstrdup failed");
Packit 6c4009
  return p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Assert that the result of an MPFR operation was exact; that is,
Packit 6c4009
   that the returned ternary value was 0.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
assert_exact (int i)
Packit 6c4009
{
Packit 6c4009
  assert (i == 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the generic type of an argument or return value type T.  */
Packit 6c4009
Packit 6c4009
static generic_value_type
Packit 6c4009
generic_arg_ret_type (arg_ret_type t)
Packit 6c4009
{
Packit 6c4009
  switch (t)
Packit 6c4009
    {
Packit 6c4009
    case type_fp:
Packit 6c4009
      return gtype_fp;
Packit 6c4009
Packit 6c4009
    case type_int:
Packit 6c4009
    case type_long:
Packit 6c4009
    case type_long_long:
Packit 6c4009
      return gtype_int;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Free a generic_value *V.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
generic_value_free (generic_value *v)
Packit 6c4009
{
Packit 6c4009
  switch (v->type)
Packit 6c4009
    {
Packit 6c4009
    case gtype_fp:
Packit 6c4009
      mpfr_clear (v->value.f);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case gtype_int:
Packit 6c4009
      mpz_clear (v->value.i);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Copy a generic_value *SRC to *DEST.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
generic_value_copy (generic_value *dest, const generic_value *src)
Packit 6c4009
{
Packit 6c4009
  dest->type = src->type;
Packit 6c4009
  switch (src->type)
Packit 6c4009
    {
Packit 6c4009
    case gtype_fp:
Packit 6c4009
      mpfr_init (dest->value.f);
Packit 6c4009
      assert_exact (mpfr_set (dest->value.f, src->value.f, MPFR_RNDN));
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case gtype_int:
Packit 6c4009
      mpz_init (dest->value.i);
Packit 6c4009
      mpz_set (dest->value.i, src->value.i);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Initialize data for floating-point formats.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
init_fp_formats (void)
Packit 6c4009
{
Packit 6c4009
  int global_max_exp = 0, global_min_subnorm_exp = 0;
Packit 6c4009
  for (fp_format f = fp_first_format; f < fp_num_formats; f++)
Packit 6c4009
    {
Packit 6c4009
      if (fp_formats[f].mant_dig + 2 > internal_precision)
Packit 6c4009
	internal_precision = fp_formats[f].mant_dig + 2;
Packit 6c4009
      if (fp_formats[f].max_exp > global_max_exp)
Packit 6c4009
	global_max_exp = fp_formats[f].max_exp;
Packit 6c4009
      int min_subnorm_exp = fp_formats[f].min_exp - fp_formats[f].mant_dig;
Packit 6c4009
      if (min_subnorm_exp < global_min_subnorm_exp)
Packit 6c4009
	global_min_subnorm_exp = min_subnorm_exp;
Packit 6c4009
      mpfr_init2 (fp_formats[f].max, fp_formats[f].mant_dig);
Packit 6c4009
      if (fp_formats[f].max_string != NULL)
Packit 6c4009
	{
Packit 6c4009
	  char *ep = NULL;
Packit 6c4009
	  assert_exact (mpfr_strtofr (fp_formats[f].max,
Packit 6c4009
				      fp_formats[f].max_string,
Packit 6c4009
				      &ep, 0, MPFR_RNDN));
Packit 6c4009
	  assert (*ep == 0);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  assert_exact (mpfr_set_ui_2exp (fp_formats[f].max, 1,
Packit 6c4009
					  fp_formats[f].max_exp,
Packit 6c4009
					  MPFR_RNDN));
Packit 6c4009
	  mpfr_nextbelow (fp_formats[f].max);
Packit 6c4009
	}
Packit 6c4009
      mpfr_init2 (fp_formats[f].min, fp_formats[f].mant_dig);
Packit 6c4009
      assert_exact (mpfr_set_ui_2exp (fp_formats[f].min, 1,
Packit 6c4009
				      fp_formats[f].min_exp - 1,
Packit 6c4009
				      MPFR_RNDN));
Packit 6c4009
      mpfr_init2 (fp_formats[f].min_plus_half, fp_formats[f].mant_dig + 1);
Packit 6c4009
      assert_exact (mpfr_set (fp_formats[f].min_plus_half,
Packit 6c4009
			      fp_formats[f].min, MPFR_RNDN));
Packit 6c4009
      mpfr_nextabove (fp_formats[f].min_plus_half);
Packit 6c4009
      mpfr_init2 (fp_formats[f].subnorm_max, fp_formats[f].mant_dig);
Packit 6c4009
      assert_exact (mpfr_set (fp_formats[f].subnorm_max, fp_formats[f].min,
Packit 6c4009
			      MPFR_RNDN));
Packit 6c4009
      mpfr_nextbelow (fp_formats[f].subnorm_max);
Packit 6c4009
      mpfr_nextbelow (fp_formats[f].subnorm_max);
Packit 6c4009
      mpfr_init2 (fp_formats[f].subnorm_min, fp_formats[f].mant_dig);
Packit 6c4009
      assert_exact (mpfr_set_ui_2exp (fp_formats[f].subnorm_min, 1,
Packit 6c4009
				      min_subnorm_exp, MPFR_RNDN));
Packit 6c4009
    }
Packit 6c4009
  mpfr_set_default_prec (internal_precision);
Packit 6c4009
  mpfr_init (global_max);
Packit 6c4009
  assert_exact (mpfr_set_ui_2exp (global_max, 1, global_max_exp, MPFR_RNDN));
Packit 6c4009
  mpfr_init (global_min);
Packit 6c4009
  assert_exact (mpfr_set_ui_2exp (global_min, 1, global_min_subnorm_exp - 1,
Packit 6c4009
				  MPFR_RNDN));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Fill in mpfr_t values for special strings in input arguments.  */
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_max (mpfr_t res0, mpfr_t res1 __attribute__ ((unused)),
Packit 6c4009
		  fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set (res0, fp_formats[format].max, MPFR_RNDN));
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_minus_max (mpfr_t res0, mpfr_t res1 __attribute__ ((unused)),
Packit 6c4009
			fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_neg (res0, fp_formats[format].max, MPFR_RNDN));
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_min (mpfr_t res0, mpfr_t res1 __attribute__ ((unused)),
Packit 6c4009
		  fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set (res0, fp_formats[format].min, MPFR_RNDN));
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_minus_min (mpfr_t res0, mpfr_t res1 __attribute__ ((unused)),
Packit 6c4009
			fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_neg (res0, fp_formats[format].min, MPFR_RNDN));
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_min_subnorm (mpfr_t res0, mpfr_t res1 __attribute__ ((unused)),
Packit 6c4009
			  fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set (res0, fp_formats[format].subnorm_min, MPFR_RNDN));
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_minus_min_subnorm (mpfr_t res0,
Packit 6c4009
				mpfr_t res1 __attribute__ ((unused)),
Packit 6c4009
				fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_neg (res0, fp_formats[format].subnorm_min, MPFR_RNDN));
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_min_subnorm_p120 (mpfr_t res0,
Packit 6c4009
			       mpfr_t res1 __attribute__ ((unused)),
Packit 6c4009
			       fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_mul_2ui (res0, fp_formats[format].subnorm_min,
Packit 6c4009
			      120, MPFR_RNDN));
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_pi (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res0, MPFR_RNDU);
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res1, MPFR_RNDD);
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_minus_pi (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res0, MPFR_RNDU);
Packit 6c4009
  assert_exact (mpfr_neg (res0, res0, MPFR_RNDN));
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res1, MPFR_RNDD);
Packit 6c4009
  assert_exact (mpfr_neg (res1, res1, MPFR_RNDN));
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_pi_2 (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res0, MPFR_RNDU);
Packit 6c4009
  assert_exact (mpfr_div_ui (res0, res0, 2, MPFR_RNDN));
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res1, MPFR_RNDD);
Packit 6c4009
  assert_exact (mpfr_div_ui (res1, res1, 2, MPFR_RNDN));
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_minus_pi_2 (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res0, MPFR_RNDU);
Packit 6c4009
  assert_exact (mpfr_div_ui (res0, res0, 2, MPFR_RNDN));
Packit 6c4009
  assert_exact (mpfr_neg (res0, res0, MPFR_RNDN));
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res1, MPFR_RNDD);
Packit 6c4009
  assert_exact (mpfr_div_ui (res1, res1, 2, MPFR_RNDN));
Packit 6c4009
  assert_exact (mpfr_neg (res1, res1, MPFR_RNDN));
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_pi_4 (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si (res0, 1, MPFR_RNDN));
Packit 6c4009
  mpfr_atan (res0, res0, MPFR_RNDU);
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si (res1, 1, MPFR_RNDN));
Packit 6c4009
  mpfr_atan (res1, res1, MPFR_RNDD);
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_pi_6 (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si_2exp (res0, 1, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_asin (res0, res0, MPFR_RNDU);
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si_2exp (res1, 1, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_asin (res1, res1, MPFR_RNDD);
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_minus_pi_6 (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si_2exp (res0, -1, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_asin (res0, res0, MPFR_RNDU);
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si_2exp (res1, -1, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_asin (res1, res1, MPFR_RNDD);
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_pi_3 (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si_2exp (res0, 1, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_acos (res0, res0, MPFR_RNDU);
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si_2exp (res1, 1, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_acos (res1, res1, MPFR_RNDD);
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_2pi_3 (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si_2exp (res0, -1, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_acos (res0, res0, MPFR_RNDU);
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si_2exp (res1, -1, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_acos (res1, res1, MPFR_RNDD);
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_2pi (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res0, MPFR_RNDU);
Packit 6c4009
  assert_exact (mpfr_mul_ui (res0, res0, 2, MPFR_RNDN));
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  mpfr_const_pi (res1, MPFR_RNDD);
Packit 6c4009
  assert_exact (mpfr_mul_ui (res1, res1, 2, MPFR_RNDN));
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_e (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si (res0, 1, MPFR_RNDN));
Packit 6c4009
  mpfr_exp (res0, res0, MPFR_RNDU);
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si (res1, 1, MPFR_RNDN));
Packit 6c4009
  mpfr_exp (res1, res1, MPFR_RNDD);
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_1_e (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si (res0, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_exp (res0, res0, MPFR_RNDU);
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si (res1, -1, MPFR_RNDN));
Packit 6c4009
  mpfr_exp (res1, res1, MPFR_RNDD);
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
special_fill_e_minus_1 (mpfr_t res0, mpfr_t res1, fp_format format)
Packit 6c4009
{
Packit 6c4009
  mpfr_init2 (res0, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si (res0, 1, MPFR_RNDN));
Packit 6c4009
  mpfr_expm1 (res0, res0, MPFR_RNDU);
Packit 6c4009
  mpfr_init2 (res1, fp_formats[format].mant_dig);
Packit 6c4009
  assert_exact (mpfr_set_si (res1, 1, MPFR_RNDN));
Packit 6c4009
  mpfr_expm1 (res1, res1, MPFR_RNDD);
Packit 6c4009
  return 2;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* A special string accepted in input arguments.  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  /* The string.  */
Packit 6c4009
  const char *str;
Packit 6c4009
  /* The function that interprets it for a given floating-point
Packit 6c4009
     format, filling in up to two mpfr_t values and returning the
Packit 6c4009
     number of values filled.  */
Packit 6c4009
  size_t (*func) (mpfr_t, mpfr_t, fp_format);
Packit 6c4009
} special_real_input;
Packit 6c4009
Packit 6c4009
/* List of special strings accepted in input arguments.  */
Packit 6c4009
Packit 6c4009
static const special_real_input special_real_inputs[] =
Packit 6c4009
  {
Packit 6c4009
    { "max", special_fill_max },
Packit 6c4009
    { "-max", special_fill_minus_max },
Packit 6c4009
    { "min", special_fill_min },
Packit 6c4009
    { "-min", special_fill_minus_min },
Packit 6c4009
    { "min_subnorm", special_fill_min_subnorm },
Packit 6c4009
    { "-min_subnorm", special_fill_minus_min_subnorm },
Packit 6c4009
    { "min_subnorm_p120", special_fill_min_subnorm_p120 },
Packit 6c4009
    { "pi", special_fill_pi },
Packit 6c4009
    { "-pi", special_fill_minus_pi },
Packit 6c4009
    { "pi/2", special_fill_pi_2 },
Packit 6c4009
    { "-pi/2", special_fill_minus_pi_2 },
Packit 6c4009
    { "pi/4", special_fill_pi_4 },
Packit 6c4009
    { "pi/6", special_fill_pi_6 },
Packit 6c4009
    { "-pi/6", special_fill_minus_pi_6 },
Packit 6c4009
    { "pi/3", special_fill_pi_3 },
Packit 6c4009
    { "2pi/3", special_fill_2pi_3 },
Packit 6c4009
    { "2pi", special_fill_2pi },
Packit 6c4009
    { "e", special_fill_e },
Packit 6c4009
    { "1/e", special_fill_1_e },
Packit 6c4009
    { "e-1", special_fill_e_minus_1 },
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* Given a real number R computed in round-to-zero mode, set the
Packit 6c4009
   lowest bit as a sticky bit if INEXACT, and saturate the exponent
Packit 6c4009
   range for very large or small values.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
adjust_real (mpfr_t r, bool inexact)
Packit 6c4009
{
Packit 6c4009
  if (!inexact)
Packit 6c4009
    return;
Packit 6c4009
  /* NaNs are exact, as are infinities in round-to-zero mode.  */
Packit 6c4009
  assert (mpfr_number_p (r));
Packit 6c4009
  if (mpfr_cmpabs (r, global_min) < 0)
Packit 6c4009
    assert_exact (mpfr_copysign (r, global_min, r, MPFR_RNDN));
Packit 6c4009
  else if (mpfr_cmpabs (r, global_max) > 0)
Packit 6c4009
    assert_exact (mpfr_copysign (r, global_max, r, MPFR_RNDN));
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      mpz_t tmp;
Packit 6c4009
      mpz_init (tmp);
Packit 6c4009
      mpfr_exp_t e = mpfr_get_z_2exp (tmp, r);
Packit 6c4009
      if (mpz_sgn (tmp) < 0)
Packit 6c4009
	{
Packit 6c4009
	  mpz_neg (tmp, tmp);
Packit 6c4009
	  mpz_setbit (tmp, 0);
Packit 6c4009
	  mpz_neg (tmp, tmp);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	mpz_setbit (tmp, 0);
Packit 6c4009
      assert_exact (mpfr_set_z_2exp (r, tmp, e, MPFR_RNDN));
Packit 6c4009
      mpz_clear (tmp);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Given a finite real number R with sticky bit, compute the roundings
Packit 6c4009
   to FORMAT in each rounding mode, storing the results in RES, the
Packit 6c4009
   before-rounding exceptions in EXC_BEFORE and the after-rounding
Packit 6c4009
   exceptions in EXC_AFTER.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
round_real (mpfr_t res[rm_num_modes],
Packit 6c4009
	    unsigned int exc_before[rm_num_modes],
Packit 6c4009
	    unsigned int exc_after[rm_num_modes],
Packit 6c4009
	    mpfr_t r, fp_format format)
Packit 6c4009
{
Packit 6c4009
  assert (mpfr_number_p (r));
Packit 6c4009
  for (rounding_mode m = rm_first_mode; m < rm_num_modes; m++)
Packit 6c4009
    {
Packit 6c4009
      mpfr_init2 (res[m], fp_formats[format].mant_dig);
Packit 6c4009
      exc_before[m] = exc_after[m] = 0;
Packit 6c4009
      bool inexact = mpfr_set (res[m], r, rounding_modes[m].mpfr_mode);
Packit 6c4009
      if (mpfr_cmpabs (res[m], fp_formats[format].max) > 0)
Packit 6c4009
	{
Packit 6c4009
	  inexact = true;
Packit 6c4009
	  exc_before[m] |= 1U << exc_overflow;
Packit 6c4009
	  exc_after[m] |= 1U << exc_overflow;
Packit 6c4009
	  bool overflow_inf;
Packit 6c4009
	  switch (m)
Packit 6c4009
	    {
Packit 6c4009
	    case rm_tonearest:
Packit 6c4009
	      overflow_inf = true;
Packit 6c4009
	      break;
Packit 6c4009
	    case rm_towardzero:
Packit 6c4009
	      overflow_inf = false;
Packit 6c4009
	      break;
Packit 6c4009
	    case rm_downward:
Packit 6c4009
	      overflow_inf = mpfr_signbit (res[m]);
Packit 6c4009
	      break;
Packit 6c4009
	    case rm_upward:
Packit 6c4009
	      overflow_inf = !mpfr_signbit (res[m]);
Packit 6c4009
	      break;
Packit 6c4009
	    default:
Packit 6c4009
	      abort ();
Packit 6c4009
	    }
Packit 6c4009
	  if (overflow_inf)
Packit 6c4009
	    mpfr_set_inf (res[m], mpfr_signbit (res[m]) ? -1 : 1);
Packit 6c4009
	  else
Packit 6c4009
	    assert_exact (mpfr_copysign (res[m], fp_formats[format].max,
Packit 6c4009
					 res[m], MPFR_RNDN));
Packit 6c4009
	}
Packit 6c4009
      if (mpfr_cmpabs (r, fp_formats[format].min) < 0)
Packit 6c4009
	{
Packit 6c4009
	  /* Tiny before rounding; may or may not be tiny after
Packit 6c4009
	     rounding, and underflow applies only if also inexact
Packit 6c4009
	     around rounding to a possibly subnormal value.  */
Packit 6c4009
	  bool tiny_after_rounding
Packit 6c4009
	    = mpfr_cmpabs (res[m], fp_formats[format].min) < 0;
Packit 6c4009
	  /* To round to a possibly subnormal value, and determine
Packit 6c4009
	     inexactness as a subnormal in the process, scale up and
Packit 6c4009
	     round to integer, then scale back down.  */
Packit 6c4009
	  mpfr_t tmp;
Packit 6c4009
	  mpfr_init (tmp);
Packit 6c4009
	  assert_exact (mpfr_mul_2si (tmp, r, (fp_formats[format].mant_dig
Packit 6c4009
					       - fp_formats[format].min_exp),
Packit 6c4009
				      MPFR_RNDN));
Packit 6c4009
	  int rint_res = mpfr_rint (tmp, tmp, rounding_modes[m].mpfr_mode);
Packit 6c4009
	  /* The integer must be representable.  */
Packit 6c4009
	  assert (rint_res == 0 || rint_res == 2 || rint_res == -2);
Packit 6c4009
	  /* If rounding to full precision was inexact, so must
Packit 6c4009
	     rounding to subnormal precision be inexact.  */
Packit 6c4009
	  if (inexact)
Packit 6c4009
	    assert (rint_res != 0);
Packit 6c4009
	  else
Packit 6c4009
	    inexact = rint_res != 0;
Packit 6c4009
	  assert_exact (mpfr_mul_2si (res[m], tmp,
Packit 6c4009
				      (fp_formats[format].min_exp
Packit 6c4009
				       - fp_formats[format].mant_dig),
Packit 6c4009
				      MPFR_RNDN));
Packit 6c4009
	  mpfr_clear (tmp);
Packit 6c4009
	  if (inexact)
Packit 6c4009
	    {
Packit 6c4009
	      exc_before[m] |= 1U << exc_underflow;
Packit 6c4009
	      if (tiny_after_rounding)
Packit 6c4009
		exc_after[m] |= 1U << exc_underflow;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      if (inexact)
Packit 6c4009
	{
Packit 6c4009
	  exc_before[m] |= 1U << exc_inexact;
Packit 6c4009
	  exc_after[m] |= 1U << exc_inexact;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Handle the input argument at ARG (NUL-terminated), updating the
Packit 6c4009
   lists of test inputs in IT accordingly.  NUM_PREV_ARGS arguments
Packit 6c4009
   are already in those lists.  If EXACT_ARGS, interpret a value given
Packit 6c4009
   as a floating-point constant exactly (it must be exact for some
Packit 6c4009
   supported format) rather than rounding up and down.  The argument,
Packit 6c4009
   of type GTYPE, comes from file FILENAME, line LINENO.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
handle_input_arg (const char *arg, input_test *it, size_t num_prev_args,
Packit 6c4009
		  generic_value_type gtype, bool exact_args,
Packit 6c4009
		  const char *filename, unsigned int lineno)
Packit 6c4009
{
Packit 6c4009
  size_t num_values = 0;
Packit 6c4009
  generic_value values[2 * fp_num_formats];
Packit 6c4009
  bool check_empty_list = false;
Packit 6c4009
  switch (gtype)
Packit 6c4009
    {
Packit 6c4009
    case gtype_fp:
Packit 6c4009
      for (fp_format f = fp_first_format; f < fp_num_formats; f++)
Packit 6c4009
	{
Packit 6c4009
	  mpfr_t extra_values[2];
Packit 6c4009
	  size_t num_extra_values = 0;
Packit 6c4009
	  for (size_t i = 0; i < ARRAY_SIZE (special_real_inputs); i++)
Packit 6c4009
	    {
Packit 6c4009
	      if (strcmp (arg, special_real_inputs[i].str) == 0)
Packit 6c4009
		{
Packit 6c4009
		  num_extra_values
Packit 6c4009
		    = special_real_inputs[i].func (extra_values[0],
Packit 6c4009
						   extra_values[1], f);
Packit 6c4009
		  assert (num_extra_values > 0
Packit 6c4009
			  && num_extra_values <= ARRAY_SIZE (extra_values));
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  if (num_extra_values == 0)
Packit 6c4009
	    {
Packit 6c4009
	      mpfr_t tmp;
Packit 6c4009
	      char *ep;
Packit 6c4009
	      if (exact_args)
Packit 6c4009
		check_empty_list = true;
Packit 6c4009
	      mpfr_init (tmp);
Packit 6c4009
	      bool inexact = mpfr_strtofr (tmp, arg, &ep, 0, MPFR_RNDZ);
Packit 6c4009
	      if (*ep != 0 || !mpfr_number_p (tmp))
Packit 6c4009
		error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
			       "bad floating-point argument: '%s'", arg);
Packit 6c4009
	      adjust_real (tmp, inexact);
Packit 6c4009
	      mpfr_t rounded[rm_num_modes];
Packit 6c4009
	      unsigned int exc_before[rm_num_modes];
Packit 6c4009
	      unsigned int exc_after[rm_num_modes];
Packit 6c4009
	      round_real (rounded, exc_before, exc_after, tmp, f);
Packit 6c4009
	      mpfr_clear (tmp);
Packit 6c4009
	      if (mpfr_number_p (rounded[rm_upward])
Packit 6c4009
		  && (!exact_args || mpfr_equal_p (rounded[rm_upward],
Packit 6c4009
						   rounded[rm_downward])))
Packit 6c4009
		{
Packit 6c4009
		  mpfr_init2 (extra_values[num_extra_values],
Packit 6c4009
			      fp_formats[f].mant_dig);
Packit 6c4009
		  assert_exact (mpfr_set (extra_values[num_extra_values],
Packit 6c4009
					  rounded[rm_upward], MPFR_RNDN));
Packit 6c4009
		  num_extra_values++;
Packit 6c4009
		}
Packit 6c4009
	      if (mpfr_number_p (rounded[rm_downward]) && !exact_args)
Packit 6c4009
		{
Packit 6c4009
		  mpfr_init2 (extra_values[num_extra_values],
Packit 6c4009
			      fp_formats[f].mant_dig);
Packit 6c4009
		  assert_exact (mpfr_set (extra_values[num_extra_values],
Packit 6c4009
					  rounded[rm_downward], MPFR_RNDN));
Packit 6c4009
		  num_extra_values++;
Packit 6c4009
		}
Packit 6c4009
	      for (rounding_mode m = rm_first_mode; m < rm_num_modes; m++)
Packit 6c4009
		mpfr_clear (rounded[m]);
Packit 6c4009
	    }
Packit 6c4009
	  for (size_t i = 0; i < num_extra_values; i++)
Packit 6c4009
	    {
Packit 6c4009
	      bool found = false;
Packit 6c4009
	      for (size_t j = 0; j < num_values; j++)
Packit 6c4009
		{
Packit 6c4009
		  if (mpfr_equal_p (values[j].value.f, extra_values[i])
Packit 6c4009
		      && ((mpfr_signbit (values[j].value.f) != 0)
Packit 6c4009
			  == (mpfr_signbit (extra_values[i]) != 0)))
Packit 6c4009
		    {
Packit 6c4009
		      found = true;
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	      if (!found)
Packit 6c4009
		{
Packit 6c4009
		  assert (num_values < ARRAY_SIZE (values));
Packit 6c4009
		  values[num_values].type = gtype_fp;
Packit 6c4009
		  mpfr_init2 (values[num_values].value.f,
Packit 6c4009
			      fp_formats[f].mant_dig);
Packit 6c4009
		  assert_exact (mpfr_set (values[num_values].value.f,
Packit 6c4009
					  extra_values[i], MPFR_RNDN));
Packit 6c4009
		  num_values++;
Packit 6c4009
		}
Packit 6c4009
	      mpfr_clear (extra_values[i]);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case gtype_int:
Packit 6c4009
      num_values = 1;
Packit 6c4009
      values[0].type = gtype_int;
Packit 6c4009
      int ret = mpz_init_set_str (values[0].value.i, arg, 0);
Packit 6c4009
      if (ret != 0)
Packit 6c4009
	error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
		       "bad integer argument: '%s'", arg);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
  if (check_empty_list && num_values == 0)
Packit 6c4009
    error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
		   "floating-point argument not exact for any format: '%s'",
Packit 6c4009
		   arg);
Packit 6c4009
  assert (num_values > 0 && num_values <= ARRAY_SIZE (values));
Packit 6c4009
  if (it->num_input_cases >= SIZE_MAX / num_values)
Packit 6c4009
    error_at_line (EXIT_FAILURE, 0, filename, lineno, "too many input cases");
Packit 6c4009
  generic_value **old_inputs = it->inputs;
Packit 6c4009
  size_t new_num_input_cases = it->num_input_cases * num_values;
Packit 6c4009
  generic_value **new_inputs = xmalloc (new_num_input_cases
Packit 6c4009
					* sizeof (new_inputs[0]));
Packit 6c4009
  for (size_t i = 0; i < it->num_input_cases; i++)
Packit 6c4009
    {
Packit 6c4009
      for (size_t j = 0; j < num_values; j++)
Packit 6c4009
	{
Packit 6c4009
	  size_t idx = i * num_values + j;
Packit 6c4009
	  new_inputs[idx] = xmalloc ((num_prev_args + 1)
Packit 6c4009
				     * sizeof (new_inputs[idx][0]));
Packit 6c4009
	  for (size_t k = 0; k < num_prev_args; k++)
Packit 6c4009
	    generic_value_copy (&new_inputs[idx][k], &old_inputs[i][k]);
Packit 6c4009
	  generic_value_copy (&new_inputs[idx][num_prev_args], &values[j]);
Packit 6c4009
	}
Packit 6c4009
      for (size_t j = 0; j < num_prev_args; j++)
Packit 6c4009
	generic_value_free (&old_inputs[i][j]);
Packit 6c4009
      free (old_inputs[i]);
Packit 6c4009
    }
Packit 6c4009
  free (old_inputs);
Packit 6c4009
  for (size_t i = 0; i < num_values; i++)
Packit 6c4009
    generic_value_free (&values[i]);
Packit 6c4009
  it->inputs = new_inputs;
Packit 6c4009
  it->num_input_cases = new_num_input_cases;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Handle the input flag ARG (NUL-terminated), storing it in *FLAG.
Packit 6c4009
   The flag comes from file FILENAME, line LINENO.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
handle_input_flag (char *arg, input_flag *flag,
Packit 6c4009
		   const char *filename, unsigned int lineno)
Packit 6c4009
{
Packit 6c4009
  char *ep = strchr (arg, ':');
Packit 6c4009
  if (ep == NULL)
Packit 6c4009
    {
Packit 6c4009
      ep = strchr (arg, 0);
Packit 6c4009
      assert (ep != NULL);
Packit 6c4009
    }
Packit 6c4009
  char c = *ep;
Packit 6c4009
  *ep = 0;
Packit 6c4009
  bool found = false;
Packit 6c4009
  for (input_flag_type i = flag_first_flag; i <= num_input_flag_types; i++)
Packit 6c4009
    {
Packit 6c4009
      if (strcmp (arg, input_flags[i]) == 0)
Packit 6c4009
	{
Packit 6c4009
	  found = true;
Packit 6c4009
	  flag->type = i;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  if (!found)
Packit 6c4009
    error_at_line (EXIT_FAILURE, 0, filename, lineno, "unknown flag: '%s'",
Packit 6c4009
		   arg);
Packit 6c4009
  *ep = c;
Packit 6c4009
  if (c == 0)
Packit 6c4009
    flag->cond = NULL;
Packit 6c4009
  else
Packit 6c4009
    flag->cond = xstrdup (ep);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Add the test LINE (file FILENAME, line LINENO) to the test
Packit 6c4009
   data.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
add_test (char *line, const char *filename, unsigned int lineno)
Packit 6c4009
{
Packit 6c4009
  size_t num_tokens = 1;
Packit 6c4009
  char *p = line;
Packit 6c4009
  while ((p = strchr (p, ' ')) != NULL)
Packit 6c4009
    {
Packit 6c4009
      num_tokens++;
Packit 6c4009
      p++;
Packit 6c4009
    }
Packit 6c4009
  if (num_tokens < 2)
Packit 6c4009
    error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
		   "line too short: '%s'", line);
Packit 6c4009
  p = strchr (line, ' ');
Packit 6c4009
  size_t func_name_len = p - line;
Packit 6c4009
  for (size_t i = 0; i < ARRAY_SIZE (test_functions); i++)
Packit 6c4009
    {
Packit 6c4009
      if (func_name_len == strlen (test_functions[i].name)
Packit 6c4009
	  && strncmp (line, test_functions[i].name, func_name_len) == 0)
Packit 6c4009
	{
Packit 6c4009
	  test_function *tf = &test_functions[i];
Packit 6c4009
	  if (num_tokens < 1 + tf->num_args)
Packit 6c4009
	    error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
			   "line too short: '%s'", line);
Packit 6c4009
	  if (tf->num_tests == tf->num_tests_alloc)
Packit 6c4009
	    {
Packit 6c4009
	      tf->num_tests_alloc = 2 * tf->num_tests_alloc + 16;
Packit 6c4009
	      tf->tests
Packit 6c4009
		= xrealloc (tf->tests,
Packit 6c4009
			    tf->num_tests_alloc * sizeof (tf->tests[0]));
Packit 6c4009
	    }
Packit 6c4009
	  input_test *it = &tf->tests[tf->num_tests];
Packit 6c4009
	  it->line = line;
Packit 6c4009
	  it->num_input_cases = 1;
Packit 6c4009
	  it->inputs = xmalloc (sizeof (it->inputs[0]));
Packit 6c4009
	  it->inputs[0] = NULL;
Packit 6c4009
	  it->old_output = NULL;
Packit 6c4009
	  p++;
Packit 6c4009
	  for (size_t j = 0; j < tf->num_args; j++)
Packit 6c4009
	    {
Packit 6c4009
	      char *ep = strchr (p, ' ');
Packit 6c4009
	      if (ep == NULL)
Packit 6c4009
		{
Packit 6c4009
		  ep = strchr (p, '\n');
Packit 6c4009
		  assert (ep != NULL);
Packit 6c4009
		}
Packit 6c4009
	      if (ep == p)
Packit 6c4009
		error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
			       "empty token in line: '%s'", line);
Packit 6c4009
	      for (char *t = p; t < ep; t++)
Packit 6c4009
		if (isspace ((unsigned char) *t))
Packit 6c4009
		  error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
				 "whitespace in token in line: '%s'", line);
Packit 6c4009
	      char c = *ep;
Packit 6c4009
	      *ep = 0;
Packit 6c4009
	      handle_input_arg (p, it, j,
Packit 6c4009
				generic_arg_ret_type (tf->arg_types[j]),
Packit 6c4009
				tf->exact_args, filename, lineno);
Packit 6c4009
	      *ep = c;
Packit 6c4009
	      p = ep + 1;
Packit 6c4009
	    }
Packit 6c4009
	  it->num_flags = num_tokens - 1 - tf->num_args;
Packit 6c4009
	  it->flags = xmalloc (it->num_flags * sizeof (it->flags[0]));
Packit 6c4009
	  for (size_t j = 0; j < it->num_flags; j++)
Packit 6c4009
	    {
Packit 6c4009
	      char *ep = strchr (p, ' ');
Packit 6c4009
	      if (ep == NULL)
Packit 6c4009
		{
Packit 6c4009
		  ep = strchr (p, '\n');
Packit 6c4009
		  assert (ep != NULL);
Packit 6c4009
		}
Packit 6c4009
	      if (ep == p)
Packit 6c4009
		error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
			       "empty token in line: '%s'", line);
Packit 6c4009
	      for (char *t = p; t < ep; t++)
Packit 6c4009
		if (isspace ((unsigned char) *t))
Packit 6c4009
		  error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
				 "whitespace in token in line: '%s'", line);
Packit 6c4009
	      char c = *ep;
Packit 6c4009
	      *ep = 0;
Packit 6c4009
	      handle_input_flag (p, &it->flags[j], filename, lineno);
Packit 6c4009
	      *ep = c;
Packit 6c4009
	      p = ep + 1;
Packit 6c4009
	    }
Packit 6c4009
	  assert (*p == 0);
Packit 6c4009
	  tf->num_tests++;
Packit 6c4009
	  return;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  error_at_line (EXIT_FAILURE, 0, filename, lineno,
Packit 6c4009
		 "unknown function in line: '%s'", line);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Read in the test input data from FILENAME.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
read_input (const char *filename)
Packit 6c4009
{
Packit 6c4009
  FILE *fp = fopen (filename, "r");
Packit 6c4009
  if (fp == NULL)
Packit 6c4009
    error (EXIT_FAILURE, errno, "open '%s'", filename);
Packit 6c4009
  unsigned int lineno = 0;
Packit 6c4009
  for (;;)
Packit 6c4009
    {
Packit 6c4009
      size_t size = 0;
Packit 6c4009
      char *line = NULL;
Packit 6c4009
      ssize_t ret = getline (&line, &size, fp);
Packit 6c4009
      if (ret == -1)
Packit 6c4009
	break;
Packit 6c4009
      lineno++;
Packit 6c4009
      if (line[0] == '#' || line[0] == '\n')
Packit 6c4009
	continue;
Packit 6c4009
      add_test (line, filename, lineno);
Packit 6c4009
    }
Packit 6c4009
  if (ferror (fp))
Packit 6c4009
    error (EXIT_FAILURE, errno, "read from '%s'", filename);
Packit 6c4009
  if (fclose (fp) != 0)
Packit 6c4009
    error (EXIT_FAILURE, errno, "close '%s'", filename);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Calculate the generic results (round-to-zero with sticky bit) for
Packit 6c4009
   the function described by CALC, with inputs INPUTS, if MODE is
Packit 6c4009
   rm_towardzero; for other modes, calculate results in that mode,
Packit 6c4009
   which must be exact zero results.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
calc_generic_results (generic_value *outputs, generic_value *inputs,
Packit 6c4009
		      const func_calc_desc *calc, rounding_mode mode)
Packit 6c4009
{
Packit 6c4009
  bool inexact;
Packit 6c4009
  int mpc_ternary;
Packit 6c4009
  mpc_t ci1, ci2, co;
Packit 6c4009
  mpfr_rnd_t mode_mpfr = rounding_modes[mode].mpfr_mode;
Packit 6c4009
  mpc_rnd_t mode_mpc = rounding_modes[mode].mpc_mode;
Packit 6c4009
Packit 6c4009
  switch (calc->method)
Packit 6c4009
    {
Packit 6c4009
    case mpfr_f_f:
Packit 6c4009
      assert (inputs[0].type == gtype_fp);
Packit 6c4009
      outputs[0].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[0].value.f);
Packit 6c4009
      inexact = calc->func.mpfr_f_f (outputs[0].value.f, inputs[0].value.f,
Packit 6c4009
				     mode_mpfr);
Packit 6c4009
      if (mode != rm_towardzero)
Packit 6c4009
	assert (!inexact && mpfr_zero_p (outputs[0].value.f));
Packit 6c4009
      adjust_real (outputs[0].value.f, inexact);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case mpfr_ff_f:
Packit 6c4009
      assert (inputs[0].type == gtype_fp);
Packit 6c4009
      assert (inputs[1].type == gtype_fp);
Packit 6c4009
      outputs[0].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[0].value.f);
Packit 6c4009
      inexact = calc->func.mpfr_ff_f (outputs[0].value.f, inputs[0].value.f,
Packit 6c4009
				      inputs[1].value.f, mode_mpfr);
Packit 6c4009
      if (mode != rm_towardzero)
Packit 6c4009
	assert (!inexact && mpfr_zero_p (outputs[0].value.f));
Packit 6c4009
      adjust_real (outputs[0].value.f, inexact);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case mpfr_fff_f:
Packit 6c4009
      assert (inputs[0].type == gtype_fp);
Packit 6c4009
      assert (inputs[1].type == gtype_fp);
Packit 6c4009
      assert (inputs[2].type == gtype_fp);
Packit 6c4009
      outputs[0].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[0].value.f);
Packit 6c4009
      inexact = calc->func.mpfr_fff_f (outputs[0].value.f, inputs[0].value.f,
Packit 6c4009
				       inputs[1].value.f, inputs[2].value.f,
Packit 6c4009
				       mode_mpfr);
Packit 6c4009
      if (mode != rm_towardzero)
Packit 6c4009
	assert (!inexact && mpfr_zero_p (outputs[0].value.f));
Packit 6c4009
      adjust_real (outputs[0].value.f, inexact);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case mpfr_f_f1:
Packit 6c4009
      assert (inputs[0].type == gtype_fp);
Packit 6c4009
      outputs[0].type = gtype_fp;
Packit 6c4009
      outputs[1].type = gtype_int;
Packit 6c4009
      mpfr_init (outputs[0].value.f);
Packit 6c4009
      int i = 0;
Packit 6c4009
      inexact = calc->func.mpfr_f_f1 (outputs[0].value.f, &i,
Packit 6c4009
				      inputs[0].value.f, mode_mpfr);
Packit 6c4009
      if (mode != rm_towardzero)
Packit 6c4009
	assert (!inexact && mpfr_zero_p (outputs[0].value.f));
Packit 6c4009
      adjust_real (outputs[0].value.f, inexact);
Packit 6c4009
      mpz_init_set_si (outputs[1].value.i, i);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case mpfr_if_f:
Packit 6c4009
      assert (inputs[0].type == gtype_int);
Packit 6c4009
      assert (inputs[1].type == gtype_fp);
Packit 6c4009
      outputs[0].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[0].value.f);
Packit 6c4009
      assert (mpz_fits_slong_p (inputs[0].value.i));
Packit 6c4009
      long l = mpz_get_si (inputs[0].value.i);
Packit 6c4009
      inexact = calc->func.mpfr_if_f (outputs[0].value.f, l,
Packit 6c4009
				      inputs[1].value.f, mode_mpfr);
Packit 6c4009
      if (mode != rm_towardzero)
Packit 6c4009
	assert (!inexact && mpfr_zero_p (outputs[0].value.f));
Packit 6c4009
      adjust_real (outputs[0].value.f, inexact);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case mpfr_f_11:
Packit 6c4009
      assert (inputs[0].type == gtype_fp);
Packit 6c4009
      outputs[0].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[0].value.f);
Packit 6c4009
      outputs[1].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[1].value.f);
Packit 6c4009
      int comb_ternary = calc->func.mpfr_f_11 (outputs[0].value.f,
Packit 6c4009
					       outputs[1].value.f,
Packit 6c4009
					       inputs[0].value.f,
Packit 6c4009
					       mode_mpfr);
Packit 6c4009
      if (mode != rm_towardzero)
Packit 6c4009
	assert (((comb_ternary & 0x3) == 0
Packit 6c4009
		 && mpfr_zero_p (outputs[0].value.f))
Packit 6c4009
		|| ((comb_ternary & 0xc) == 0
Packit 6c4009
		    && mpfr_zero_p (outputs[1].value.f)));
Packit 6c4009
      adjust_real (outputs[0].value.f, (comb_ternary & 0x3) != 0);
Packit 6c4009
      adjust_real (outputs[1].value.f, (comb_ternary & 0xc) != 0);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case mpc_c_f:
Packit 6c4009
      assert (inputs[0].type == gtype_fp);
Packit 6c4009
      assert (inputs[1].type == gtype_fp);
Packit 6c4009
      outputs[0].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[0].value.f);
Packit 6c4009
      mpc_init2 (ci1, internal_precision);
Packit 6c4009
      assert_exact (mpc_set_fr_fr (ci1, inputs[0].value.f, inputs[1].value.f,
Packit 6c4009
				   MPC_RNDNN));
Packit 6c4009
      inexact = calc->func.mpc_c_f (outputs[0].value.f, ci1, mode_mpfr);
Packit 6c4009
      if (mode != rm_towardzero)
Packit 6c4009
	assert (!inexact && mpfr_zero_p (outputs[0].value.f));
Packit 6c4009
      adjust_real (outputs[0].value.f, inexact);
Packit 6c4009
      mpc_clear (ci1);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case mpc_c_c:
Packit 6c4009
      assert (inputs[0].type == gtype_fp);
Packit 6c4009
      assert (inputs[1].type == gtype_fp);
Packit 6c4009
      outputs[0].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[0].value.f);
Packit 6c4009
      outputs[1].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[1].value.f);
Packit 6c4009
      mpc_init2 (ci1, internal_precision);
Packit 6c4009
      mpc_init2 (co, internal_precision);
Packit 6c4009
      assert_exact (mpc_set_fr_fr (ci1, inputs[0].value.f, inputs[1].value.f,
Packit 6c4009
				   MPC_RNDNN));
Packit 6c4009
      mpc_ternary = calc->func.mpc_c_c (co, ci1, mode_mpc);
Packit 6c4009
      if (mode != rm_towardzero)
Packit 6c4009
	assert ((!MPC_INEX_RE (mpc_ternary)
Packit 6c4009
		 && mpfr_zero_p (mpc_realref (co)))
Packit 6c4009
		|| (!MPC_INEX_IM (mpc_ternary)
Packit 6c4009
		    && mpfr_zero_p (mpc_imagref (co))));
Packit 6c4009
      assert_exact (mpfr_set (outputs[0].value.f, mpc_realref (co),
Packit 6c4009
			      MPFR_RNDN));
Packit 6c4009
      assert_exact (mpfr_set (outputs[1].value.f, mpc_imagref (co),
Packit 6c4009
			      MPFR_RNDN));
Packit 6c4009
      adjust_real (outputs[0].value.f, MPC_INEX_RE (mpc_ternary));
Packit 6c4009
      adjust_real (outputs[1].value.f, MPC_INEX_IM (mpc_ternary));
Packit 6c4009
      mpc_clear (ci1);
Packit 6c4009
      mpc_clear (co);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case mpc_cc_c:
Packit 6c4009
      assert (inputs[0].type == gtype_fp);
Packit 6c4009
      assert (inputs[1].type == gtype_fp);
Packit 6c4009
      assert (inputs[2].type == gtype_fp);
Packit 6c4009
      assert (inputs[3].type == gtype_fp);
Packit 6c4009
      outputs[0].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[0].value.f);
Packit 6c4009
      outputs[1].type = gtype_fp;
Packit 6c4009
      mpfr_init (outputs[1].value.f);
Packit 6c4009
      mpc_init2 (ci1, internal_precision);
Packit 6c4009
      mpc_init2 (ci2, internal_precision);
Packit 6c4009
      mpc_init2 (co, internal_precision);
Packit 6c4009
      assert_exact (mpc_set_fr_fr (ci1, inputs[0].value.f, inputs[1].value.f,
Packit 6c4009
				   MPC_RNDNN));
Packit 6c4009
      assert_exact (mpc_set_fr_fr (ci2, inputs[2].value.f, inputs[3].value.f,
Packit 6c4009
				   MPC_RNDNN));
Packit 6c4009
      mpc_ternary = calc->func.mpc_cc_c (co, ci1, ci2, mode_mpc);
Packit 6c4009
      if (mode != rm_towardzero)
Packit 6c4009
	assert ((!MPC_INEX_RE (mpc_ternary)
Packit 6c4009
		 && mpfr_zero_p (mpc_realref (co)))
Packit 6c4009
		|| (!MPC_INEX_IM (mpc_ternary)
Packit 6c4009
		    && mpfr_zero_p (mpc_imagref (co))));
Packit 6c4009
      assert_exact (mpfr_set (outputs[0].value.f, mpc_realref (co),
Packit 6c4009
			      MPFR_RNDN));
Packit 6c4009
      assert_exact (mpfr_set (outputs[1].value.f, mpc_imagref (co),
Packit 6c4009
			      MPFR_RNDN));
Packit 6c4009
      adjust_real (outputs[0].value.f, MPC_INEX_RE (mpc_ternary));
Packit 6c4009
      adjust_real (outputs[1].value.f, MPC_INEX_IM (mpc_ternary));
Packit 6c4009
      mpc_clear (ci1);
Packit 6c4009
      mpc_clear (ci2);
Packit 6c4009
      mpc_clear (co);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the number of bits for integer type TYPE, where "long" has
Packit 6c4009
   LONG_BITS bits (32 or 64).  */
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
int_type_bits (arg_ret_type type, int long_bits)
Packit 6c4009
{
Packit 6c4009
  assert (long_bits == 32 || long_bits == 64);
Packit 6c4009
  switch (type)
Packit 6c4009
    {
Packit 6c4009
    case type_int:
Packit 6c4009
      return 32;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case type_long:
Packit 6c4009
      return long_bits;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case type_long_long:
Packit 6c4009
      return 64;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Check whether an integer Z fits a given type TYPE, where "long" has
Packit 6c4009
   LONG_BITS bits (32 or 64).  */
Packit 6c4009
Packit 6c4009
static bool
Packit 6c4009
int_fits_type (mpz_t z, arg_ret_type type, int long_bits)
Packit 6c4009
{
Packit 6c4009
  int bits = int_type_bits (type, long_bits);
Packit 6c4009
  bool ret = true;
Packit 6c4009
  mpz_t t;
Packit 6c4009
  mpz_init (t);
Packit 6c4009
  mpz_ui_pow_ui (t, 2, bits - 1);
Packit 6c4009
  if (mpz_cmp (z, t) >= 0)
Packit 6c4009
    ret = false;
Packit 6c4009
  mpz_neg (t, t);
Packit 6c4009
  if (mpz_cmp (z, t) < 0)
Packit 6c4009
    ret = false;
Packit 6c4009
  mpz_clear (t);
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Print a generic value V to FP (name FILENAME), preceded by a space,
Packit 6c4009
   for type TYPE, LONG_BITS bits per long, printing " IGNORE" instead
Packit 6c4009
   if IGNORE.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
output_generic_value (FILE *fp, const char *filename, const generic_value *v,
Packit 6c4009
		      bool ignore, arg_ret_type type, int long_bits)
Packit 6c4009
{
Packit 6c4009
  if (ignore)
Packit 6c4009
    {
Packit 6c4009
      if (fputs (" IGNORE", fp) < 0)
Packit 6c4009
	error (EXIT_FAILURE, errno, "write to '%s'", filename);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
  assert (v->type == generic_arg_ret_type (type));
Packit 6c4009
  const char *suffix;
Packit 6c4009
  switch (type)
Packit 6c4009
    {
Packit 6c4009
    case type_fp:
Packit 6c4009
      suffix = "";
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case type_int:
Packit 6c4009
      suffix = "";
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case type_long:
Packit 6c4009
      suffix = "L";
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case type_long_long:
Packit 6c4009
      suffix = "LL";
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
  switch (v->type)
Packit 6c4009
    {
Packit 6c4009
    case gtype_fp:
Packit 6c4009
      if (mpfr_inf_p (v->value.f))
Packit 6c4009
	{
Packit 6c4009
	  if (fputs ((mpfr_signbit (v->value.f)
Packit 6c4009
		      ? " minus_infty" : " plus_infty"), fp) < 0)
Packit 6c4009
	    error (EXIT_FAILURE, errno, "write to '%s'", filename);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  assert (mpfr_number_p (v->value.f));
Packit 6c4009
	  if (mpfr_fprintf (fp, " %Ra%s", v->value.f, suffix) < 0)
Packit 6c4009
	    error (EXIT_FAILURE, errno, "mpfr_fprintf to '%s'", filename);
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case gtype_int: ;
Packit 6c4009
      int bits = int_type_bits (type, long_bits);
Packit 6c4009
      mpz_t tmp;
Packit 6c4009
      mpz_init (tmp);
Packit 6c4009
      mpz_ui_pow_ui (tmp, 2, bits - 1);
Packit 6c4009
      mpz_neg (tmp, tmp);
Packit 6c4009
      if (mpz_cmp (v->value.i, tmp) == 0)
Packit 6c4009
	{
Packit 6c4009
	  mpz_add_ui (tmp, tmp, 1);
Packit 6c4009
	  if (mpfr_fprintf (fp, " (%Zd%s-1)", tmp, suffix) < 0)
Packit 6c4009
	    error (EXIT_FAILURE, errno, "mpfr_fprintf to '%s'", filename);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  if (mpfr_fprintf (fp, " %Zd%s", v->value.i, suffix) < 0)
Packit 6c4009
	    error (EXIT_FAILURE, errno, "mpfr_fprintf to '%s'", filename);
Packit 6c4009
	}
Packit 6c4009
      mpz_clear (tmp);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Generate test output to FP (name FILENAME) for test function TF
Packit 6c4009
   (rounding results to a narrower type if NARROW), input test IT,
Packit 6c4009
   choice of input values INPUTS.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
output_for_one_input_case (FILE *fp, const char *filename, test_function *tf,
Packit 6c4009
			   bool narrow, input_test *it, generic_value *inputs)
Packit 6c4009
{
Packit 6c4009
  bool long_bits_matters = false;
Packit 6c4009
  bool fits_long32 = true;
Packit 6c4009
  for (size_t i = 0; i < tf->num_args; i++)
Packit 6c4009
    {
Packit 6c4009
      generic_value_type gtype = generic_arg_ret_type (tf->arg_types[i]);
Packit 6c4009
      assert (inputs[i].type == gtype);
Packit 6c4009
      if (gtype == gtype_int)
Packit 6c4009
	{
Packit 6c4009
	  bool fits_64 = int_fits_type (inputs[i].value.i, tf->arg_types[i],
Packit 6c4009
					64);
Packit 6c4009
	  if (!fits_64)
Packit 6c4009
	    return;
Packit 6c4009
	  if (tf->arg_types[i] == type_long
Packit 6c4009
	      && !int_fits_type (inputs[i].value.i, tf->arg_types[i], 32))
Packit 6c4009
	    {
Packit 6c4009
	      long_bits_matters = true;
Packit 6c4009
	      fits_long32 = false;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  generic_value generic_outputs[MAX_NRET];
Packit 6c4009
  calc_generic_results (generic_outputs, inputs, &tf->calc, rm_towardzero);
Packit 6c4009
  bool ignore_output_long32[MAX_NRET] = { false };
Packit 6c4009
  bool ignore_output_long64[MAX_NRET] = { false };
Packit 6c4009
  for (size_t i = 0; i < tf->num_ret; i++)
Packit 6c4009
    {
Packit 6c4009
      assert (generic_outputs[i].type
Packit 6c4009
	      == generic_arg_ret_type (tf->ret_types[i]));
Packit 6c4009
      switch (generic_outputs[i].type)
Packit 6c4009
	{
Packit 6c4009
	case gtype_fp:
Packit 6c4009
	  if (!mpfr_number_p (generic_outputs[i].value.f))
Packit 6c4009
	    goto out; /* Result is NaN or exact infinity.  */
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case gtype_int:
Packit 6c4009
	  ignore_output_long32[i] = !int_fits_type (generic_outputs[i].value.i,
Packit 6c4009
						    tf->ret_types[i], 32);
Packit 6c4009
	  ignore_output_long64[i] = !int_fits_type (generic_outputs[i].value.i,
Packit 6c4009
						    tf->ret_types[i], 64);
Packit 6c4009
	  if (ignore_output_long32[i] != ignore_output_long64[i])
Packit 6c4009
	    long_bits_matters = true;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	default:
Packit 6c4009
	  abort ();
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  /* Iterate over relevant sizes of long and floating-point formats.  */
Packit 6c4009
  for (int long_bits = 32; long_bits <= 64; long_bits += 32)
Packit 6c4009
    {
Packit 6c4009
      if (long_bits == 32 && !fits_long32)
Packit 6c4009
	continue;
Packit 6c4009
      if (long_bits == 64 && !long_bits_matters)
Packit 6c4009
	continue;
Packit 6c4009
      const char *long_cond;
Packit 6c4009
      if (long_bits_matters)
Packit 6c4009
	long_cond = (long_bits == 32 ? ":long32" : ":long64");
Packit 6c4009
      else
Packit 6c4009
	long_cond = "";
Packit 6c4009
      bool *ignore_output = (long_bits == 32
Packit 6c4009
			     ? ignore_output_long32
Packit 6c4009
			     : ignore_output_long64);
Packit 6c4009
      for (fp_format f = fp_first_format; f < fp_num_formats; f++)
Packit 6c4009
	{
Packit 6c4009
	  bool fits = true;
Packit 6c4009
	  mpfr_t res[rm_num_modes];
Packit 6c4009
	  unsigned int exc_before[rm_num_modes];
Packit 6c4009
	  unsigned int exc_after[rm_num_modes];
Packit 6c4009
	  bool have_fp_arg = false;
Packit 6c4009
	  int max_exp = 0;
Packit 6c4009
	  int num_ones = 0;
Packit 6c4009
	  int min_exp = 0;
Packit 6c4009
	  int max_prec = 0;
Packit 6c4009
	  for (size_t i = 0; i < tf->num_args; i++)
Packit 6c4009
	    {
Packit 6c4009
	      if (inputs[i].type == gtype_fp)
Packit 6c4009
		{
Packit 6c4009
		  if (narrow)
Packit 6c4009
		    {
Packit 6c4009
		      if (mpfr_zero_p (inputs[i].value.f))
Packit 6c4009
			continue;
Packit 6c4009
		      assert (mpfr_regular_p (inputs[i].value.f));
Packit 6c4009
		      int this_exp, this_num_ones, this_min_exp, this_prec;
Packit 6c4009
		      mpz_t tmp;
Packit 6c4009
		      mpz_init (tmp);
Packit 6c4009
		      mpfr_exp_t e = mpfr_get_z_2exp (tmp, inputs[i].value.f);
Packit 6c4009
		      if (mpz_sgn (tmp) < 0)
Packit 6c4009
			mpz_neg (tmp, tmp);
Packit 6c4009
		      size_t bits = mpz_sizeinbase (tmp, 2);
Packit 6c4009
		      mp_bitcnt_t tz = mpz_scan1 (tmp, 0);
Packit 6c4009
		      this_min_exp = e + tz;
Packit 6c4009
		      this_prec = bits - tz;
Packit 6c4009
		      assert (this_prec > 0);
Packit 6c4009
		      this_exp = this_min_exp + this_prec - 1;
Packit 6c4009
		      assert (this_exp
Packit 6c4009
			      == mpfr_get_exp (inputs[i].value.f) - 1);
Packit 6c4009
		      this_num_ones = 1;
Packit 6c4009
		      while ((size_t) this_num_ones < bits
Packit 6c4009
			     && mpz_tstbit (tmp, bits - 1 - this_num_ones))
Packit 6c4009
			this_num_ones++;
Packit 6c4009
		      mpz_clear (tmp);
Packit 6c4009
		      if (have_fp_arg)
Packit 6c4009
			{
Packit 6c4009
			  if (this_exp > max_exp
Packit 6c4009
			      || (this_exp == max_exp
Packit 6c4009
				  && this_num_ones > num_ones))
Packit 6c4009
			    {
Packit 6c4009
			      max_exp = this_exp;
Packit 6c4009
			      num_ones = this_num_ones;
Packit 6c4009
			    }
Packit 6c4009
			  if (this_min_exp < min_exp)
Packit 6c4009
			    min_exp = this_min_exp;
Packit 6c4009
			  if (this_prec > max_prec)
Packit 6c4009
			    max_prec = this_prec;
Packit 6c4009
			}
Packit 6c4009
		      else
Packit 6c4009
			{
Packit 6c4009
			  max_exp = this_exp;
Packit 6c4009
			  num_ones = this_num_ones;
Packit 6c4009
			  min_exp = this_min_exp;
Packit 6c4009
			  max_prec = this_prec;
Packit 6c4009
			}
Packit 6c4009
		      have_fp_arg = true;
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      round_real (res, exc_before, exc_after,
Packit 6c4009
				  inputs[i].value.f, f);
Packit 6c4009
		      if (!mpfr_equal_p (res[rm_tonearest], inputs[i].value.f))
Packit 6c4009
			fits = false;
Packit 6c4009
		      for (rounding_mode m = rm_first_mode;
Packit 6c4009
			   m < rm_num_modes;
Packit 6c4009
			   m++)
Packit 6c4009
			mpfr_clear (res[m]);
Packit 6c4009
		      if (!fits)
Packit 6c4009
			break;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  if (!fits)
Packit 6c4009
	    continue;
Packit 6c4009
	  /* The inputs fit this type if required to do so, so compute
Packit 6c4009
	     the ideal outputs and exceptions.  */
Packit 6c4009
	  mpfr_t all_res[MAX_NRET][rm_num_modes];
Packit 6c4009
	  unsigned int all_exc_before[MAX_NRET][rm_num_modes];
Packit 6c4009
	  unsigned int all_exc_after[MAX_NRET][rm_num_modes];
Packit 6c4009
	  unsigned int merged_exc_before[rm_num_modes] = { 0 };
Packit 6c4009
	  unsigned int merged_exc_after[rm_num_modes] = { 0 };
Packit 6c4009
	  /* For functions not exactly determined, track whether
Packit 6c4009
	     underflow is required (some result is inexact, and
Packit 6c4009
	     magnitude does not exceed the greatest magnitude
Packit 6c4009
	     subnormal), and permitted (not an exact zero, and
Packit 6c4009
	     magnitude does not exceed the least magnitude
Packit 6c4009
	     normal).  */
Packit 6c4009
	  bool must_underflow = false;
Packit 6c4009
	  bool may_underflow = false;
Packit 6c4009
	  for (size_t i = 0; i < tf->num_ret; i++)
Packit 6c4009
	    {
Packit 6c4009
	      switch (generic_outputs[i].type)
Packit 6c4009
		{
Packit 6c4009
		case gtype_fp:
Packit 6c4009
		  round_real (all_res[i], all_exc_before[i], all_exc_after[i],
Packit 6c4009
			      generic_outputs[i].value.f, f);
Packit 6c4009
		  for (rounding_mode m = rm_first_mode; m < rm_num_modes; m++)
Packit 6c4009
		    {
Packit 6c4009
		      merged_exc_before[m] |= all_exc_before[i][m];
Packit 6c4009
		      merged_exc_after[m] |= all_exc_after[i][m];
Packit 6c4009
		      if (!tf->exact)
Packit 6c4009
			{
Packit 6c4009
			  must_underflow
Packit 6c4009
			    |= ((all_exc_before[i][m]
Packit 6c4009
				 & (1U << exc_inexact)) != 0
Packit 6c4009
				&& (mpfr_cmpabs (generic_outputs[i].value.f,
Packit 6c4009
						fp_formats[f].subnorm_max)
Packit 6c4009
				    <= 0));
Packit 6c4009
			  may_underflow
Packit 6c4009
			    |= (!mpfr_zero_p (generic_outputs[i].value.f)
Packit 6c4009
				&& (mpfr_cmpabs (generic_outputs[i].value.f,
Packit 6c4009
						 fp_formats[f].min_plus_half)
Packit 6c4009
				    <= 0));
Packit 6c4009
			}
Packit 6c4009
		      /* If the result is an exact zero, the sign may
Packit 6c4009
			 depend on the rounding mode, so recompute it
Packit 6c4009
			 directly in that mode.  */
Packit 6c4009
		      if (mpfr_zero_p (all_res[i][m])
Packit 6c4009
			  && (all_exc_before[i][m] & (1U << exc_inexact)) == 0)
Packit 6c4009
			{
Packit 6c4009
			  generic_value outputs_rm[MAX_NRET];
Packit 6c4009
			  calc_generic_results (outputs_rm, inputs,
Packit 6c4009
						&tf->calc, m);
Packit 6c4009
			  assert_exact (mpfr_set (all_res[i][m],
Packit 6c4009
						  outputs_rm[i].value.f,
Packit 6c4009
						  MPFR_RNDN));
Packit 6c4009
			  for (size_t j = 0; j < tf->num_ret; j++)
Packit 6c4009
			    generic_value_free (&outputs_rm[j]);
Packit 6c4009
			}
Packit 6c4009
		    }
Packit 6c4009
		  break;
Packit 6c4009
Packit 6c4009
		case gtype_int:
Packit 6c4009
		  if (ignore_output[i])
Packit 6c4009
		    for (rounding_mode m = rm_first_mode;
Packit 6c4009
			 m < rm_num_modes;
Packit 6c4009
			 m++)
Packit 6c4009
		      {
Packit 6c4009
			merged_exc_before[m] |= 1U << exc_invalid;
Packit 6c4009
			merged_exc_after[m] |= 1U << exc_invalid;
Packit 6c4009
		      }
Packit 6c4009
		  break;
Packit 6c4009
Packit 6c4009
		default:
Packit 6c4009
		  abort ();
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  assert (may_underflow || !must_underflow);
Packit 6c4009
	  for (rounding_mode m = rm_first_mode; m < rm_num_modes; m++)
Packit 6c4009
	    {
Packit 6c4009
	      bool before_after_matters
Packit 6c4009
		= tf->exact && merged_exc_before[m] != merged_exc_after[m];
Packit 6c4009
	      if (before_after_matters)
Packit 6c4009
		{
Packit 6c4009
		  assert ((merged_exc_before[m] ^ merged_exc_after[m])
Packit 6c4009
			  == (1U << exc_underflow));
Packit 6c4009
		  assert ((merged_exc_before[m] & (1U << exc_underflow)) != 0);
Packit 6c4009
		}
Packit 6c4009
	      unsigned int merged_exc = merged_exc_before[m];
Packit 6c4009
	      if (narrow)
Packit 6c4009
		{
Packit 6c4009
		  if (fprintf (fp, "= %s %s %s%s:arg_fmt(%d,%d,%d,%d)",
Packit 6c4009
			       tf->name, rounding_modes[m].name,
Packit 6c4009
			       fp_formats[f].name, long_cond, max_exp,
Packit 6c4009
			       num_ones, min_exp, max_prec) < 0)
Packit 6c4009
		    error (EXIT_FAILURE, errno, "write to '%s'", filename);
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  if (fprintf (fp, "= %s %s %s%s", tf->name,
Packit 6c4009
			       rounding_modes[m].name, fp_formats[f].name,
Packit 6c4009
			       long_cond) < 0)
Packit 6c4009
		    error (EXIT_FAILURE, errno, "write to '%s'", filename);
Packit 6c4009
		}
Packit 6c4009
	      /* Print inputs.  */
Packit 6c4009
	      for (size_t i = 0; i < tf->num_args; i++)
Packit 6c4009
		output_generic_value (fp, filename, &inputs[i], false,
Packit 6c4009
				      tf->arg_types[i], long_bits);
Packit 6c4009
	      if (fputs (" :", fp) < 0)
Packit 6c4009
		error (EXIT_FAILURE, errno, "write to '%s'", filename);
Packit 6c4009
	      /* Print outputs.  */
Packit 6c4009
	      bool must_erange = false;
Packit 6c4009
	      bool some_underflow_zero = false;
Packit 6c4009
	      for (size_t i = 0; i < tf->num_ret; i++)
Packit 6c4009
		{
Packit 6c4009
		  generic_value g;
Packit 6c4009
		  g.type = generic_outputs[i].type;
Packit 6c4009
		  switch (g.type)
Packit 6c4009
		    {
Packit 6c4009
		    case gtype_fp:
Packit 6c4009
		      if (mpfr_inf_p (all_res[i][m])
Packit 6c4009
			  && (all_exc_before[i][m]
Packit 6c4009
			      & (1U << exc_overflow)) != 0)
Packit 6c4009
			must_erange = true;
Packit 6c4009
		      if (mpfr_zero_p (all_res[i][m])
Packit 6c4009
			  && (tf->exact
Packit 6c4009
			      || mpfr_zero_p (all_res[i][rm_tonearest]))
Packit 6c4009
			  && (all_exc_before[i][m]
Packit 6c4009
			      & (1U << exc_underflow)) != 0)
Packit 6c4009
			must_erange = true;
Packit 6c4009
		      if (mpfr_zero_p (all_res[i][rm_towardzero])
Packit 6c4009
			  && (all_exc_before[i][m]
Packit 6c4009
			      & (1U << exc_underflow)) != 0)
Packit 6c4009
			some_underflow_zero = true;
Packit 6c4009
		      mpfr_init2 (g.value.f, fp_formats[f].mant_dig);
Packit 6c4009
		      assert_exact (mpfr_set (g.value.f, all_res[i][m],
Packit 6c4009
					      MPFR_RNDN));
Packit 6c4009
		      break;
Packit 6c4009
Packit 6c4009
		    case gtype_int:
Packit 6c4009
		      mpz_init (g.value.i);
Packit 6c4009
		      mpz_set (g.value.i, generic_outputs[i].value.i);
Packit 6c4009
		      break;
Packit 6c4009
Packit 6c4009
		    default:
Packit 6c4009
		      abort ();
Packit 6c4009
		    }
Packit 6c4009
		  output_generic_value (fp, filename, &g, ignore_output[i],
Packit 6c4009
					tf->ret_types[i], long_bits);
Packit 6c4009
		  generic_value_free (&g);
Packit 6c4009
		}
Packit 6c4009
	      if (fputs (" :", fp) < 0)
Packit 6c4009
		error (EXIT_FAILURE, errno, "write to '%s'", filename);
Packit 6c4009
	      /* Print miscellaneous flags (passed through from
Packit 6c4009
		 input).  */
Packit 6c4009
	      for (size_t i = 0; i < it->num_flags; i++)
Packit 6c4009
		switch (it->flags[i].type)
Packit 6c4009
		  {
Packit 6c4009
		  case flag_no_test_inline:
Packit 6c4009
		  case flag_ignore_zero_inf_sign:
Packit 6c4009
		  case flag_xfail:
Packit 6c4009
		    if (fprintf (fp, " %s%s",
Packit 6c4009
				 input_flags[it->flags[i].type],
Packit 6c4009
				 (it->flags[i].cond
Packit 6c4009
				  ? it->flags[i].cond
Packit 6c4009
				  : "")) < 0)
Packit 6c4009
		      error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
			     filename);
Packit 6c4009
		    break;
Packit 6c4009
		  case flag_xfail_rounding:
Packit 6c4009
		    if (m != rm_tonearest)
Packit 6c4009
		      if (fprintf (fp, " xfail%s",
Packit 6c4009
				   (it->flags[i].cond
Packit 6c4009
				    ? it->flags[i].cond
Packit 6c4009
				    : "")) < 0)
Packit 6c4009
			error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
			       filename);
Packit 6c4009
		    break;
Packit 6c4009
		  default:
Packit 6c4009
		    break;
Packit 6c4009
		  }
Packit 6c4009
	      /* For the ibm128 format, expect incorrect overflowing
Packit 6c4009
		 results in rounding modes other than to nearest;
Packit 6c4009
		 likewise incorrect results where the result may
Packit 6c4009
		 underflow to 0.  */
Packit 6c4009
	      if (f == fp_ldbl_128ibm
Packit 6c4009
		  && m != rm_tonearest
Packit 6c4009
		  && (some_underflow_zero
Packit 6c4009
		      || (merged_exc_before[m] & (1U << exc_overflow)) != 0))
Packit 6c4009
		if (fputs (" xfail:ibm128-libgcc", fp) < 0)
Packit 6c4009
		  error (EXIT_FAILURE, errno, "write to '%s'", filename);
Packit 6c4009
	      /* Print exception flags and compute errno
Packit 6c4009
		 expectations where not already computed.  */
Packit 6c4009
	      bool may_edom = false;
Packit 6c4009
	      bool must_edom = false;
Packit 6c4009
	      bool may_erange = must_erange || may_underflow;
Packit 6c4009
	      for (fp_exception e = exc_first_exception;
Packit 6c4009
		   e < exc_num_exceptions;
Packit 6c4009
		   e++)
Packit 6c4009
		{
Packit 6c4009
		  bool expect_e = (merged_exc & (1U << e)) != 0;
Packit 6c4009
		  bool e_optional = false;
Packit 6c4009
		  switch (e)
Packit 6c4009
		    {
Packit 6c4009
		    case exc_divbyzero:
Packit 6c4009
		      if (expect_e)
Packit 6c4009
			may_erange = must_erange = true;
Packit 6c4009
		      break;
Packit 6c4009
Packit 6c4009
		    case exc_inexact:
Packit 6c4009
		      if (!tf->exact)
Packit 6c4009
			e_optional = true;
Packit 6c4009
		      break;
Packit 6c4009
Packit 6c4009
		    case exc_invalid:
Packit 6c4009
		      if (expect_e)
Packit 6c4009
			may_edom = must_edom = true;
Packit 6c4009
		      break;
Packit 6c4009
Packit 6c4009
		    case exc_overflow:
Packit 6c4009
		      if (expect_e)
Packit 6c4009
			may_erange = true;
Packit 6c4009
		      break;
Packit 6c4009
Packit 6c4009
		    case exc_underflow:
Packit 6c4009
		      if (expect_e)
Packit 6c4009
			may_erange = true;
Packit 6c4009
		      if (must_underflow)
Packit 6c4009
			assert (expect_e);
Packit 6c4009
		      if (may_underflow && !must_underflow)
Packit 6c4009
			e_optional = true;
Packit 6c4009
		      break;
Packit 6c4009
Packit 6c4009
		    default:
Packit 6c4009
		      abort ();
Packit 6c4009
		    }
Packit 6c4009
		  if (e_optional)
Packit 6c4009
		    {
Packit 6c4009
		      assert (!before_after_matters);
Packit 6c4009
		      if (fprintf (fp, " %s-ok", exceptions[e]) < 0)
Packit 6c4009
			error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
			       filename);
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      if (expect_e)
Packit 6c4009
			if (fprintf (fp, " %s", exceptions[e]) < 0)
Packit 6c4009
			  error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
				 filename);
Packit 6c4009
		      if (before_after_matters && e == exc_underflow)
Packit 6c4009
			if (fputs (":before-rounding", fp) < 0)
Packit 6c4009
			  error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
				 filename);
Packit 6c4009
		      for (int after = 0; after <= 1; after++)
Packit 6c4009
			{
Packit 6c4009
			  bool expect_e_here = expect_e;
Packit 6c4009
			  if (after == 1 && (!before_after_matters
Packit 6c4009
					     || e != exc_underflow))
Packit 6c4009
			    continue;
Packit 6c4009
			  const char *after_cond;
Packit 6c4009
			  if (before_after_matters && e == exc_underflow)
Packit 6c4009
			    {
Packit 6c4009
			      after_cond = (after
Packit 6c4009
					    ? ":after-rounding"
Packit 6c4009
					    : ":before-rounding");
Packit 6c4009
			      expect_e_here = !after;
Packit 6c4009
			    }
Packit 6c4009
			  else
Packit 6c4009
			    after_cond = "";
Packit 6c4009
			  input_flag_type okflag;
Packit 6c4009
			  okflag = (expect_e_here
Packit 6c4009
				    ? flag_missing_first
Packit 6c4009
				    : flag_spurious_first) + e;
Packit 6c4009
			  for (size_t i = 0; i < it->num_flags; i++)
Packit 6c4009
			    if (it->flags[i].type == okflag)
Packit 6c4009
			      if (fprintf (fp, " %s-ok%s%s",
Packit 6c4009
					   exceptions[e],
Packit 6c4009
					   (it->flags[i].cond
Packit 6c4009
					    ? it->flags[i].cond
Packit 6c4009
					    : ""), after_cond) < 0)
Packit 6c4009
				error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
				       filename);
Packit 6c4009
			}
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	      /* Print errno expectations.  */
Packit 6c4009
	      if (tf->complex_fn)
Packit 6c4009
		{
Packit 6c4009
		  must_edom = false;
Packit 6c4009
		  must_erange = false;
Packit 6c4009
		}
Packit 6c4009
	      if (may_edom && !must_edom)
Packit 6c4009
		{
Packit 6c4009
		  if (fputs (" errno-edom-ok", fp) < 0)
Packit 6c4009
		    error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
			   filename);
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  if (must_edom)
Packit 6c4009
		    if (fputs (" errno-edom", fp) < 0)
Packit 6c4009
		      error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
			     filename);
Packit 6c4009
		  input_flag_type okflag = (must_edom
Packit 6c4009
					    ? flag_missing_errno
Packit 6c4009
					    : flag_spurious_errno);
Packit 6c4009
		  for (size_t i = 0; i < it->num_flags; i++)
Packit 6c4009
		    if (it->flags[i].type == okflag)
Packit 6c4009
		      if (fprintf (fp, " errno-edom-ok%s",
Packit 6c4009
				   (it->flags[i].cond
Packit 6c4009
				    ? it->flags[i].cond
Packit 6c4009
				    : "")) < 0)
Packit 6c4009
			error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
			       filename);
Packit 6c4009
		}
Packit 6c4009
	      if (before_after_matters)
Packit 6c4009
		assert (may_erange && !must_erange);
Packit 6c4009
	      if (may_erange && !must_erange)
Packit 6c4009
		{
Packit 6c4009
		  if (fprintf (fp, " errno-erange-ok%s",
Packit 6c4009
			       (before_after_matters
Packit 6c4009
				? ":before-rounding"
Packit 6c4009
				: "")) < 0)
Packit 6c4009
		    error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
			   filename);
Packit 6c4009
		}
Packit 6c4009
	      if (before_after_matters || !(may_erange && !must_erange))
Packit 6c4009
		{
Packit 6c4009
		  if (must_erange)
Packit 6c4009
		    if (fputs (" errno-erange", fp) < 0)
Packit 6c4009
		      error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
			     filename);
Packit 6c4009
		  input_flag_type okflag = (must_erange
Packit 6c4009
					    ? flag_missing_errno
Packit 6c4009
					    : flag_spurious_errno);
Packit 6c4009
		  for (size_t i = 0; i < it->num_flags; i++)
Packit 6c4009
		    if (it->flags[i].type == okflag)
Packit 6c4009
		      if (fprintf (fp, " errno-erange-ok%s%s",
Packit 6c4009
				   (it->flags[i].cond
Packit 6c4009
				    ? it->flags[i].cond
Packit 6c4009
				    : ""),
Packit 6c4009
				   (before_after_matters
Packit 6c4009
				    ? ":after-rounding"
Packit 6c4009
				    : "")) < 0)
Packit 6c4009
			error (EXIT_FAILURE, errno, "write to '%s'",
Packit 6c4009
			       filename);
Packit 6c4009
		}
Packit 6c4009
	      if (putc ('\n', fp) < 0)
Packit 6c4009
		error (EXIT_FAILURE, errno, "write to '%s'", filename);
Packit 6c4009
	    }
Packit 6c4009
	  for (size_t i = 0; i < tf->num_ret; i++)
Packit 6c4009
	    {
Packit 6c4009
	      if (generic_outputs[i].type == gtype_fp)
Packit 6c4009
		for (rounding_mode m = rm_first_mode; m < rm_num_modes; m++)
Packit 6c4009
		  mpfr_clear (all_res[i][m]);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
 out:
Packit 6c4009
  for (size_t i = 0; i < tf->num_ret; i++)
Packit 6c4009
    generic_value_free (&generic_outputs[i]);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Generate test output data for FUNCTION to FILENAME.  The function
Packit 6c4009
   is interpreted as rounding its results to a narrower type if
Packit 6c4009
   NARROW.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
generate_output (const char *function, bool narrow, const char *filename)
Packit 6c4009
{
Packit 6c4009
  FILE *fp = fopen (filename, "w");
Packit 6c4009
  if (fp == NULL)
Packit 6c4009
    error (EXIT_FAILURE, errno, "open '%s'", filename);
Packit 6c4009
  for (size_t i = 0; i < ARRAY_SIZE (test_functions); i++)
Packit 6c4009
    {
Packit 6c4009
      test_function *tf = &test_functions[i];
Packit 6c4009
      if (strcmp (tf->name, function) != 0)
Packit 6c4009
	continue;
Packit 6c4009
      for (size_t j = 0; j < tf->num_tests; j++)
Packit 6c4009
	{
Packit 6c4009
	  input_test *it = &tf->tests[j];
Packit 6c4009
	  if (fputs (it->line, fp) < 0)
Packit 6c4009
	    error (EXIT_FAILURE, errno, "write to '%s'", filename);
Packit 6c4009
	  for (size_t k = 0; k < it->num_input_cases; k++)
Packit 6c4009
	    output_for_one_input_case (fp, filename, tf, narrow,
Packit 6c4009
				       it, it->inputs[k]);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  if (fclose (fp) != 0)
Packit 6c4009
    error (EXIT_FAILURE, errno, "close '%s'", filename);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
main (int argc, char **argv)
Packit 6c4009
{
Packit 6c4009
  if (argc != 4
Packit 6c4009
      && !(argc == 5 && strcmp (argv[1], "--narrow") == 0))
Packit 6c4009
    error (EXIT_FAILURE, 0,
Packit 6c4009
	   "usage: gen-auto-libm-tests [--narrow] <input> <func> <output>");
Packit 6c4009
  bool narrow;
Packit 6c4009
  const char *input_filename = argv[1];
Packit 6c4009
  const char *function = argv[2];
Packit 6c4009
  const char *output_filename = argv[3];
Packit 6c4009
  if (argc == 4)
Packit 6c4009
    {
Packit 6c4009
      narrow = false;
Packit 6c4009
      input_filename = argv[1];
Packit 6c4009
      function = argv[2];
Packit 6c4009
      output_filename = argv[3];
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      narrow = true;
Packit 6c4009
      input_filename = argv[2];
Packit 6c4009
      function = argv[3];
Packit 6c4009
      output_filename = argv[4];
Packit 6c4009
    }
Packit 6c4009
  init_fp_formats ();
Packit 6c4009
  read_input (input_filename);
Packit 6c4009
  generate_output (function, narrow, output_filename);
Packit 6c4009
  exit (EXIT_SUCCESS);
Packit 6c4009
}