Commit 0dfe15e5 authored by Robert Sprowson's avatar Robert Sprowson Committed by ROOL
Browse files

Add accelerated elementary functions

In order to reduce reliance on FPA, where we rely on the FPA transcendentals in various places which are subsequently caught and emulated via FPEmulator, expose VFP implementations of these for wider use. They are the base elementary functions corresponding to SIN/COS/TAN/ASN/ACS/ATN/POL/LOG/LGN/EXP/POW and as a bonus an FMA for pre-VFPv4 variants.

Function signatures follow their C standard definition and a generic APCS to allow their use from high level languages.

The FMA implementation comes from OpenLibm, translated by hand from C, and the accompanying test bed checks for bit identical results to ARM's instruction. For that to make sense clearly it needs to be run on something with VFPv4 otherwise it's comparing itself with itself!

When not available in hardware the elementary functions call across to these slower software implementations via a VFused macro.

Makefile: Add the new object files
VFPSupport: New SWI name, and reason flags
GetAll.s: Get the maths helpers
Macros.s: Some helper macros for bit manipulation of FP numbers
Module.s: New SWI
SupportCode.s: Error handler to recover R12 and optionally throw an error

Tested with a special version of BASICVFP which replaces the FPA transcendentals with a call to VFPSupport instead.

Version 0.15. Tagged as 'VFPSupport-0_15'
parent 72147877
......@@ -41,7 +41,9 @@ SUPPORTCODE ?= ${DEFSUPPORTCODE}
COMPONENT = VFPSupport
ASMHDRS = VFPSupport
OBJS = GetAll
FUSEDOBJS = Fused32 Fused64
TRANSOBJS = Trig32 Trig64 ArcTrig32 ArcTrig64 Power32 Power64
OBJS = GetAll ${FUSEDOBJS} ${TRANSOBJS}
HDRS =
CMHGFILE =
ASMDEFINES += -PD "SupportCode SETL {${SUPPORTCODE}}"
......
|
| Copyright (c) 2012, RISC OS Open Ltd
| All rights reserved.
|
| Redistribution and use in source and binary forms, with or without
| modification, are permitted provided that the following conditions are met:
| * Redistributions of source code must retain the above copyright
| notice, this list of conditions and the following disclaimer.
| * Redistributions in binary form must reproduce the above copyright
| notice, this list of conditions and the following disclaimer in the
| documentation and/or other materials provided with the distribution.
| * Neither the name of RISC OS Open Ltd nor the names of its contributors
| may be used to endorse or promote products derived from this software
| without specific prior written permission.
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
| POSSIBILITY OF SUCH DAMAGE.
|
Dir <Obey$Dir>
amu_machine all THROWBACK=-throwback
|
| Copyright (c) 2012, RISC OS Open Ltd
| All rights reserved.
|
| Redistribution and use in source and binary forms, with or without
| modification, are permitted provided that the following conditions are met:
| * Redistributions of source code must retain the above copyright
| notice, this list of conditions and the following disclaimer.
| * Redistributions in binary form must reproduce the above copyright
| notice, this list of conditions and the following disclaimer in the
| documentation and/or other materials provided with the distribution.
| * Neither the name of RISC OS Open Ltd nor the names of its contributors
| may be used to endorse or promote products derived from this software
| without specific prior written permission.
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
| POSSIBILITY OF SUCH DAMAGE.
|
Dir <Obey$Dir>
amu_machine clean
stripdepnd
#
# Copyright (c) 2021, RISC OS Open Ltd
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of RISC OS Open Ltd nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Makefile for Elementary function tester
#
COMPONENT = Elementary
OBJS = TestBed TestVeneer
include CApp
# Dynamic dependencies:
/*
* Copyright (c) 2021 RISC OS Open Limited
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of RISC OS Open Ltd nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdint.h>
#include "crlibm.h"
typedef union
{
uint64_t i;
double d;
} convert64_t;
typedef union
{
uint32_t i;
float f;
} convert32_t;
#define CRLIBM32_1ARG(name) \
uint32_t crlibm32_ ## name (uint32_t a1) \
{ \
convert32_t ac1; \
ac1.i = a1; \
ac1.f = (float)name ## _rn((double)ac1.f); \
return ac1.i; \
}
#define CRLIBM32_2ARG(name) \
uint32_t crlibm32_ ## name (uint32_t a1, uint32_t a2) \
{ \
convert32_t ac1, ac2; \
ac1.i = a1; \
ac2.i = a2; \
ac1.f = (float)name ## _rn((double)ac1.f, (double)ac2.f); \
return ac1.i; \
}
#define CRLIBM64_1ARG(name) \
uint64_t crlibm64_ ## name (uint64_t a1) \
{ \
convert64_t ac1; \
ac1.i = a1; \
ac1.d = name ## _rn(ac1.d); \
return ac1.i; \
}
#define CRLIBM64_2ARG(name) \
uint64_t crlibm64_ ## name (uint64_t a1, uint64_t a2) \
{ \
convert64_t ac1, ac2; \
ac1.i = a1; \
ac2.i = a2; \
ac1.d = name ## _rn(ac1.d, ac2.d); \
return ac1.i; \
}
uint32_t crlibm32_atan2(uint32_t y, uint32_t x) { return 0; /* MIA */ }
uint64_t crlibm64_atan2(uint64_t y, uint64_t x) { return 0; /* MIA */ }
CRLIBM32_1ARG(sin)
CRLIBM32_1ARG(cos)
CRLIBM32_1ARG(tan)
CRLIBM32_1ARG(asin)
CRLIBM32_1ARG(acos)
CRLIBM32_1ARG(atan)
CRLIBM32_1ARG(log)
CRLIBM32_1ARG(log10)
CRLIBM32_1ARG(exp)
CRLIBM32_2ARG(pow)
CRLIBM64_1ARG(sin)
CRLIBM64_1ARG(cos)
CRLIBM64_1ARG(tan)
CRLIBM64_1ARG(asin)
CRLIBM64_1ARG(acos)
CRLIBM64_1ARG(atan)
CRLIBM64_1ARG(log)
CRLIBM64_1ARG(log10)
CRLIBM64_1ARG(exp)
CRLIBM64_2ARG(pow)
/*
* Copyright (c) 2021 RISC OS Open Limited
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of RISC OS Open Ltd nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
/* Select the single or double precision */
#define CALL_FP_SIZE 64
/* Select an implementation */
#define CALL_FPA_OPCODES 0
#define CALL_VFP_TRANSCENDENTALS 1
#define CALL_CRLIBM 0
/* Which one is considered golden? */
#define CALL_AND_RECORD CALL_CRLIBM
/* Verbosity */
#define QUIET true /* Only report differences */
#define QUIET1ULP true /* Ignore 1 ulp differences */
/* Helpful macros */
#define UNUSED(k) (k) = (k)
#define STRINGIFY(s) STRING(s)
#define STRING(s) #s
#define NELEMENTS(a) (sizeof(a) / sizeof(a[0]))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
/* Special values */
#define ONE ((value_t)1)
#define INFP32 0x7F800000
#define INFM32 0xFF800000
#define SNaN32 0x7F800666
#define QNaN32 0x7FC00000
#define INFP64 0x7FF0000000000000uLL
#define INFM64 0xFFF0000000000000uLL
#define SNaN64 0x7FF0000000000666uLL
#define QNaN64 0x7FF8000000000000uLL
#if CALL_FP_SIZE == 32
typedef uint32_t value_t;
#define MANT_BITS 23
#define EXPO_BITS 8
#define SIGN_BITS 1
#define SIGN_BIT (1uLL<<31)
#define FMT "%08x"
#define ABS_VAL(a) labs((int32_t)(a))
#define ANY_NAN(a) (((a & ~SIGN_BIT) >> MANT_BITS) == (QNaN32 >> MANT_BITS))
#else
typedef uint64_t value_t;
#define MANT_BITS 52
#define EXPO_BITS 11
#define SIGN_BITS 1
#define SIGN_BIT (1uLL<<63)
#define FMT "%016llx"
#define ABS_VAL(a) llabs((int64_t)(a))
#define ANY_NAN(a) (((a & ~SIGN_BIT) >> MANT_BITS) == (QNaN64 >> MANT_BITS))
#endif
typedef value_t (*fn1_t)(value_t);
typedef value_t (*fn2_t)(value_t, value_t);
/* Floating point status flags (assumes FPA and VFP match up) */
#define FPSCR_IOC (1 << 0)
#define FPSCR_DZC (1 << 1)
#define FPSCR_OFC (1 << 2)
#define FPSCR_UFC (1 << 3)
#define FPSCR_IXC (1 << 4)
#define FPSCR_IDC (1 << 7)
/* Configure to use FPA opcodes */
#if CALL_FPA_OPCODES
#define CALL_PREPARE /* Nothing */
#define CALL_CLEARUP /* Nothing */
extern uint32_t fpa_fpsr(uint32_t, uint32_t);
#define EXCEPTIONS_ALL 0x1F
#define EXCEPTIONS_CLEAR fpa_fpsr(0x1F, 0)
#define EXCEPTIONS_PENDING (fpa_fpsr(0, 0) & 0xF) /* Ignore inexact */
#define EXCEPTIONS_QUIET fpa_fpsr(0x1F0000, 0)
#if CALL_FP_SIZE == 32
#define CALL_NAME(base) STRINGIFY(base), (void (*)(void))fpaop32_ ## base
#define DECLARE_NAME1(base) uint32_t fpaop32_ ## base (uint32_t)
#define DECLARE_NAME2(base) uint32_t fpaop32_ ## base (uint32_t, uint32_t)
#else
#define CALL_NAME(base) STRINGIFY(base), (void (*)(void))fpaop64_ ## base
#define DECLARE_NAME1(base) uint64_t fpaop64_ ## base (uint64_t)
#define DECLARE_NAME2(base) uint64_t fpaop64_ ## base (uint64_t, uint64_t)
#endif
#endif
/* Configure to use VFP transcendental support functions */
#if CALL_VFP_TRANSCENDENTALS
#define VFPSupport_CreateContext 0x58EC1
#define VFPSupport_DestroyContext 0x58EC2
#define VFPSupport_Transcendentals 0x58ECA
#define CALL_PREPARE void *myctx, *prevctx; \
_swix(VFPSupport_CreateContext, _INR(0,3) | _OUTR(0,1), 0x80000001, 16, 0, 0, &myctx, &prevctx); \
_swix(VFPSupport_Transcendentals, _IN(0) | _OUTR(1,2), 0, &vfp_fns32, &vfp_fns64)
#define CALL_CLEARUP _swix(VFPSupport_DestroyContext, _INR(0,1), myctx, prevctx)
extern uint32_t vfp_fpscr(uint32_t, uint32_t);
#define EXCEPTIONS_ALL 0x9F
#define EXCEPTIONS_CLEAR vfp_fpscr(0x9F, 0)
#define EXCEPTIONS_PENDING (vfp_fpscr(0, 0) & 0xF) /* Ignore inexact and input denormal */
#define EXCEPTIONS_QUIET vfp_fpscr(0x9F00, 0)
#if CALL_FP_SIZE == 32
#define CALL_NAME(base) STRINGIFY(base), (void (*)(void))vfpfn32_ ## base
#define DECLARE_NAME1(base) uint32_t vfpfn32_ ## base (uint32_t)
#define DECLARE_NAME2(base) uint32_t vfpfn32_ ## base (uint32_t, uint32_t)
#else
#define CALL_NAME(base) STRINGIFY(base), (void (*)(void))vfpfn64_ ## base
#define DECLARE_NAME1(base) uint64_t vfpfn64_ ## base (uint64_t)
#define DECLARE_NAME2(base) uint64_t vfpfn64_ ## base (uint64_t, uint64_t)
#endif
#endif
/* Configure to use correctly rounded libm */
#if CALL_CRLIBM
#define CALL_PREPARE unsigned long long prevctx = crlibm_init();
#define CALL_CLEARUP crlibm_exit(prevctx);
#define EXCEPTIONS_CLEAR 0 /* Nothing */
#define EXCEPTIONS_PENDING 0 /* Nothing */
#define EXCEPTIONS_QUIET 0 /* Nothing */
#if CALL_FP_SIZE == 32
#define CALL_NAME(base) STRINGIFY(base), (void (*)(void))crlibm32_ ## base
#define DECLARE_NAME1(base) uint32_t crlibm32_ ## base (uint32_t)
#define DECLARE_NAME2(base) uint32_t crlibm32_ ## base (uint32_t, uint32_t)
#else
#define CALL_NAME(base) STRINGIFY(base), (void (*)(void))crlibm64_ ## base
#define DECLARE_NAME1(base) uint64_t crlibm64_ ## base (uint64_t)
#define DECLARE_NAME2(base) uint64_t crlibm64_ ## base (uint64_t, uint64_t)
#endif
#endif
/* Formulate distinct names */
extern DECLARE_NAME1(sin);
extern DECLARE_NAME1(cos);
extern DECLARE_NAME1(tan);
extern DECLARE_NAME1(asin);
extern DECLARE_NAME1(acos);
extern DECLARE_NAME1(atan);
extern DECLARE_NAME2(atan2);
extern DECLARE_NAME1(exp);
extern DECLARE_NAME2(pow);
extern DECLARE_NAME1(log);
extern DECLARE_NAME1(log10);
/* Types describing the tests */
typedef struct
{
bool present;
uint64_t lo64;
uint64_t hi64;
uint32_t lo32;
uint32_t hi32;
} range_t;
typedef struct
{
bool present;
range_t positive;
range_t negative;
} arg_t;
typedef struct
{
bool present;
uint64_t in64;
uint32_t in32;
} param_t;
typedef struct
{
char *displayname;
void (*fn)(void);
arg_t args[2];
} test_t;
typedef struct
{
char *displayname;
void (*fn)(void);
param_t params[2];
uint64_t out64;
uint32_t out32;
uint8_t mask; /* Exception bits of interest */
uint8_t flags; /* Exception bit state */
} exception_t;
/* Specific headers */
#ifdef __riscos
#include "swis.h"
#endif
#if CALL_CRLIBM
#include "crlibm.h"
#endif
#include "TestTable.c"
extern void *vfp_fns32, *vfp_fns64;
void *vfp_fns32, *vfp_fns64;
static size_t maxerrbits;
static void loopsetup(value_t *lo, value_t *hi, const range_t *range)
{
#if CALL_FP_SIZE == 32
*lo = range->lo32;
*hi = range->hi32;
#else
*lo = range->lo64;
*hi = range->hi64;
#endif
}
static void edgesetup(value_t *arg0, value_t *arg1, value_t *expect, const exception_t *edge)
{
#if CALL_FP_SIZE == 32
*arg0 = edge->params[0].in32;
*arg1 = edge->params[1].in32;
*expect = edge->out32;
#else
*arg0 = edge->params[0].in64;
*arg1 = edge->params[1].in64;
*expect = edge->out64;
#endif
}
static void processresult(value_t arg0, value_t arg1, value_t result, size_t i, FILE *handle)
{
value_t golden;
bool quiet = QUIET, same = true;
#if CALL_AND_RECORD
fprintf(handle, FMT "\n", result);
UNUSED(golden);
#else
if (handle != NULL)
{
value_t diff;
if (fscanf(handle, FMT "\n", &golden) != 1)
{
printf("Error reading test result\n");
}
if (ANY_NAN(golden) && ANY_NAN(result))
{
/* Don't care about NaN signs */
result = golden;
}
/* Compare our result with the golden result */
diff = ABS_VAL(golden - result);
#if QUIET1ULP
if (diff > 1uLL) same = quiet = false;
#else
if (diff != 0) same = quiet = false;
#endif
if (!same)
{
if (diff > 65536uLL)
{
/* Serious! */
maxerrbits = 16;
}
else
{
uint32_t lo = (uint32_t)diff;
int32_t errbits;
for (errbits = 31; errbits >= 0; errbits--)
{
if (lo & (1uL << errbits)) break;
}
errbits++;
maxerrbits = MAX(errbits, maxerrbits);
}
}
}
#endif
if (tests[i].args[1].present)
{
if (!quiet) printf("%s(" FMT ", " FMT ") = " FMT, tests[i].displayname, arg0, arg1, result);
}
else
{
if (!quiet) printf("%s(" FMT ") = " FMT, tests[i].displayname, arg0, result);
}
if (EXCEPTIONS_PENDING)
{
if (!quiet) printf(" and exception!");
}
if (!quiet) putchar('\n');
if (!same)
{
printf(" expected " FMT "\n", golden);
}
}
/*
* Brute force check input combinations over a prescribed range of validity
*/
static void testvalues(void)
{
size_t i, mj, ej, mk, ek;
size_t sign, step;
value_t arg0, arg1, lim0, lim1, base0, base1;
value_t add, result;
fn1_t fn1;
fn2_t fn2;
EXCEPTIONS_QUIET;
for (i = 0; i < NELEMENTS(tests); i++)
{
FILE *handle = NULL;
char name[32];
sprintf(name, "test%i", i);
printf("Test %i of %ib %s\n", i, CALL_FP_SIZE, tests[i].displayname);
#if CALL_AND_RECORD
handle = fopen(name, "w");
if (handle == NULL)
{
printf(" unable to create %s for writing\n", name);
exit(EXIT_FAILURE);
}
#else
handle = fopen(name, "r");
if (handle == NULL)
{
printf(" skipping golden value checks as no %s data\n", name);
/* OK to continue if not there though */
}
#endif
#if CALL_FP_SIZE == 32
step = 1;
#else
step = tests[i].args[1].present ? 12 : 1; /* Tame explosive O(N^2) time */
#endif
maxerrbits = 0;
for (sign = 0; sign < 4; sign++)
{
/* Doing this sign at all? */
switch (sign)
{
case 0:
if (tests[i].args[0].positive.present && !tests[i].args[1].present) break;
if (tests[i].args[0].positive.present && tests[i].args[1].positive.present) break;
continue;
case 1:
if (tests[i].args[0].negative.present && !tests[i].args[1].present) break;
if (tests[i].args[0].negative.present && tests[i].args[1].positive.present) break;
continue;
case 2:
if (!tests[i].args[1].present) continue;
if (tests[i].args[0].positive.present && tests[i].args[1].negative.present) break;
continue;
case 3:
if (!tests[i].args[1].present) continue;
if (tests[i].args[0].negative.present && tests[i].args[1].negative.present) break;
continue;
}
/* Always at least 1 arg */
loopsetup(&base0, &lim0, (sign & 1) ? &tests[i].args[0].negative
: &tests[i].args[0].positive);
for (ej = 0; ej < (1 << EXPO_BITS); ej = ej + step)
{
arg0 = base0 + ((value_t)ej << MANT_BITS);
for (mj = 0; mj < MANT_BITS; mj++)
{
if (sign & 1) arg0 = arg0 | (ONE << (CALL_FP_SIZE - 1));
if (tests[i].args[1].present)
{
/* Here for 2 args */
loopsetup(&base1, &lim1, (sign & 2) ? &tests[i].args[1].negative
: &tests[i].args[1].positive);
for (ek = 0; ek < (1 << EXPO_BITS); ek = ek + step)
{