Commit f464cdae authored by Kevin Bracey's avatar Kevin Bracey
Browse files

Added the following C99 features:

  * snprintf(), vsnprintf(), vfscanf(), vscanf(), vsscanf()
  * hh, j, z and t printf length modifiers (indicating char, intmax_t, size_t
    and ptrdiff_t respectively)
  * Hexadecimal floating-point printing and scanning (%a/%A)
  * %F printf() specifier (upper-case form of %F)
  * Input/output of NaNs and Infinities
  * imaxdiv_t, imaxdiv(), strtoimax(), strtoumax() (simulated through macros)
  * <fenv.h>: feclearexcept(), fegetexceptflag(), feraiseexcept(),
              fesetexceptflag(), fetestexcept(), fegetround(), fesetround(),
              fegetenv(), feholdexcept(), fesetenv(), feupdateenv()
  * FLT_EVAL_METHOD, DECIMAL_DIG
  * hypot(), hypotf(), fabsf(), fdim(), fdimf(), fmax(), fmaxf(), fmin(),
    fminf()
  * INFINITY, NAN, fpclassify(), isfinite(), isinf(), isnan(), isnormal(),
    signbit(), copysign(), copysignf(), nan(), nanf(), nextafter(),
    nextafterf() isgreater(), isgreaterequal(), isless(), islessequal(),
    islessgreater(), isunordered()

This involves adding 36 new entries to the stubs. Current versions of the C
library will not fault client programs with such larger stubs, but will fill
in the extra entries with junk. Programs requiring the new functions will have
to RMEnsure this version of the Shared C Library.

This version of the C library has been fixed so that in future, any extra
unknown stubs entries will be filled in with a branch to zero, rather than
corrupted.

Requires cc 5.41 or later, both to build, and to make use of some of the extra
facilities.


Version 5.37. Tagged as 'RISC_OSLib-5_37'
......@@ -277,7 +277,7 @@ EXPORTS = ${MODWRAP} \
ANSI_OBJS =\
o.alloc o.armprof o.armsys o.clib o.ctype o.error o.fpprintf \
o.kernel o.locale o.math o.memcpset o.overmgr o.printf o.scanf \
o.signal o.sort o.stdio o.stdlib o.string o.swiv o.time
o.signal o.sort o.stdio o.stdlib o.string o.swiv o.time o.fenv
RM_OBJS =\
rm_o.k_modbody \
......@@ -299,6 +299,7 @@ RM_OBJS =\
rm_o.stdlib \
rm_o.string \
rm_o.time \
rm_o.fenv \
rm_o.swiv \
rm_o.cl_spare
......@@ -605,6 +606,7 @@ CLIB:h.swis: derived.swis
CLIB:h.assert: clib.h.assert ; ${CP} clib.h.assert $@ ${CPFLAGS}
CLIB:h.ctype: clib.h.ctype; ${CP} clib.h.ctype $@ ${CPFLAGS}
CLIB:h.errno: clib.h.errno; ${CP} clib.h.errno $@ ${CPFLAGS}
CLIB:h.fenv: clib.h.fenv; ${CP} clib.h.fenv $@ ${CPFLAGS}
CLIB:h.float: clib.h.float; ${CP} clib.h.float $@ ${CPFLAGS}
CLIB:h.inttypes: clib.h.inttypes; ${CP} clib.h.inttypes $@ ${CPFLAGS}
CLIB:h.iso646: clib.h.iso646; ${CP} clib.h.iso646 $@ ${CPFLAGS}
......
......@@ -12,14 +12,14 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "5.36"
Module_Version SETA 536
Module_MajorVersion SETS "5.37"
Module_Version SETA 537
Module_MinorVersion SETS ""
Module_Date SETS "22 Feb 2002"
Module_ApplicationDate2 SETS "22-Feb-02"
Module_ApplicationDate4 SETS "22-Feb-2002"
Module_Date SETS "21 Mar 2002"
Module_ApplicationDate2 SETS "21-Mar-02"
Module_ApplicationDate4 SETS "21-Mar-2002"
Module_ComponentName SETS "RISC_OSLib"
Module_ComponentPath SETS "RiscOS/Sources/Lib/RISC_OSLib"
Module_FullVersion SETS "5.36"
Module_HelpVersion SETS "5.36 (22 Feb 2002)"
Module_FullVersion SETS "5.37"
Module_HelpVersion SETS "5.37 (21 Mar 2002)"
END
/* (5.36)
/* (5.37)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.62.
*
*/
#define Module_MajorVersion_CMHG 5.36
#define Module_MajorVersion_CMHG 5.37
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 22 Feb 2002
#define Module_Date_CMHG 21 Mar 2002
#define Module_MajorVersion "5.36"
#define Module_Version 536
#define Module_MajorVersion "5.37"
#define Module_Version 537
#define Module_MinorVersion ""
#define Module_Date "22 Feb 2002"
#define Module_Date "21 Mar 2002"
#define Module_ApplicationDate2 "22-Feb-02"
#define Module_ApplicationDate4 "22-Feb-2002"
#define Module_ApplicationDate2 "21-Mar-02"
#define Module_ApplicationDate4 "21-Mar-2002"
#define Module_ComponentName "RISC_OSLib"
#define Module_ComponentPath "RiscOS/Sources/Lib/RISC_OSLib"
#define Module_FullVersion "5.36"
#define Module_HelpVersion "5.36 (22 Feb 2002)"
#define Module_LibraryVersionInfo "5:36"
#define Module_FullVersion "5.37"
#define Module_HelpVersion "5.37 (21 Mar 2002)"
#define Module_LibraryVersionInfo "5:37"
......@@ -53,6 +53,7 @@ extern int __vfprintf(FILE *fp, const char *fmt,
#define _SHORTSPEC 0100
#define _PADZERO 0200 /* *** DEPRECATED FEATURE *** */
#define _FPCONV 0400
#define _CHARSPEC 01000
#ifndef NO_FLOATING_POINT
......@@ -284,24 +285,24 @@ static int fp_digits(char *buff, double d)
#endif /* HOST_HAS_BCD_FLT */
static int fp_addexp(char *buff, int len, int dx, int ch)
{ int dxDiv10;
static int fp_addexp(char *buff, int len, int dx, int ch, int min)
{
char tmp[10];
int n=0;
buff[len++] = ch;
if (dx<0) { dx = -dx; buff[len++] = '-'; }
else buff[len++] = '+';
if (dx >= 1000)
{ int dxDiv1000 = _kernel_sdiv(1000, dx);
buff[len++] = '0' + dxDiv1000;
dx = dx - dxDiv1000 * 1000;
}
if (dx >= 100)
{ int dxDiv100 = _kernel_sdiv(100, dx);
buff[len++] = '0' + dxDiv100;
dx = dx - dxDiv100 * 100;
while (dx > 0 || n < min)
{
tmp[n++] = '0' + dx % 10;
dx /= 10;
}
dxDiv10 = _kernel_sdiv10(dx);
buff[len++] = '0' + dxDiv10;
buff[len++] = '0' + dx - dxDiv10 * 10;
while (n)
buff[len++] = tmp[--n];
return len;
}
......@@ -315,18 +316,42 @@ static int fp_display(int ch, double *lvd, char buff[], int flags,
int *lvafter_dot)
{ int len = 0;
double d = *lvd;
switch (ch)
{
/* The following code places characters in the buffer buff[] */
/* to print the floating point number given as d. */
/* It is given flags that indicate what format is required and how */
/* many digits precision are needed. */
if (!isfinite(d))
{ int upper = ch < 'a';
if (signbit(d)) *lvprefix = "-";
else
*lvprefix = (flags&_SIGNED) ? "+" :
(flags&_BLANKER) ? " " : "";
if (isinf(d))
{ if (upper)
buff[0] = 'I', buff[1] = 'N', buff[2] = 'F';
else
buff[0] = 'i', buff[1] = 'n', buff[2] = 'f';
}
else
{ if (upper)
buff[0] = 'N', buff[1] = 'A', buff[2] = 'N';
else
buff[0] = 'n', buff[1] = 'a', buff[2] = 'n';
}
*lvbefore_dot = -1;
*lvafter_dot = -1;
return 3;
}
switch (ch)
{
/* Floating point values are ALWAYS converted into 18 decimal digits */
/* (the largest number possible reasonable) to start with, and rounding */
/* is then performed on this character representation. This is intended */
/* to avoid all possibility of boundary effects when numbers like .9999 */
/* are being displayed. */
case 'f':
case 'F':
{ int dx = fp_digits(buff, d);
if (dx & 1) *lvprefix = "-";
else
......@@ -467,7 +492,7 @@ static int fp_display(int ch, double *lvd, char buff[], int flags,
}
if (ch!='f') /* sets 'f' if it prints in f format */
/* and 'e' or 'E' if in e format. */
len = fp_addexp(buff, len, dx, ch + ('e'-'g'));
len = fp_addexp(buff, len, dx, ch + ('e'-'g'), 2);
}
break;
case 'e':
......@@ -489,7 +514,67 @@ static int fp_display(int ch, double *lvd, char buff[], int flags,
else buff[1] = *decimal_point;
/* Deal with trailing zeros for excessive precision requests */
if (*lvafter_dot>0) buff[len++] = '>';
len = fp_addexp(buff, len, dx, ch);
len = fp_addexp(buff, len, dx, ch, 2);
}
break;
/* Hexadecimal printing - this is pretty easy. Output is in the form */
/* [-]0xh.hhhhp<+|->d, where there is one hexadecimal digit (non-zero if */
/* normalised) before the '.', and precision digits after the '.' */
case 'a':
case 'A':
{ unsigned whi, wlo, bx, i;
const char *hextab;
hextab = ch=='a' ? "0123456789abcdef" : "0123456789ABCDEF";
whi = ((unsigned *)lvd)[0];
wlo = ((unsigned *)lvd)[1];
/* take 3 off exponent because putting 4 bits before . */
bx = ((whi >> 20) & 0x7FF) - 0x3FF;
if (whi & 0x80000000) *lvprefix = (ch=='a'?"-0x":"-0X");
else
*lvprefix = (flags&_SIGNED) ? (ch=='a'?"+0x":"+0X") :
(flags&_BLANKER) ? (ch=='a'?" 0x":" 0X") :
(ch=='a'?"0x":"0X");
if ((whi&0x7FFFFFFF)|wlo)
{ if (bx == -0x3FF)
bx = -0x3FE;
else
whi |= 0x00100000;
}
else
bx = 0;
whi &= 0x001FFFFF;
buff[0] = '0';
for (i=1; i<=6; i++)
buff[i] = hextab[(whi >> (24-i*4)) & 0xf];
for (i=7; i<=14; i++)
buff[i] = hextab[(wlo >> (56-i*4)) & 0xf];
if (!(flags&_PRECGIVEN))
{ *lvprecision = 0;
for (i=13; i>=1; i--)
if (buff[i+1] != '0')
{ *lvprecision = i;
break;
}
}
else if (*lvprecision>13)
{ *lvafter_dot = *lvprecision - 13;
*lvprecision = 13;
}
len = *lvprecision + 2;
buff[0] = buff[1];
if ((*lvprecision==0) && !(flags&_VARIANT)) len = 1;
else buff[1] = *decimal_point;
/* Deal with trailing zeros for excessive precision requests */
if (*lvafter_dot>0) buff[len++] = '>';
len = fp_addexp(buff, len, bx, ch + ('p'-'a'), 1);
}
break;
}
......@@ -547,6 +632,25 @@ int sprintf(char *buff, const char *fmt, ...)
return(length);
}
int snprintf(char *buff, size_t n, const char *fmt, ...)
{
FILE hack;
va_list a;
/*************************************************************************/
/* Note that this code interacts in a dubious way with the putc macro. */
/*************************************************************************/
int length;
va_start(a, fmt);
memclr(&hack, sizeof(FILE));
hack.__flag = _IOSTRG+_IOWRITE;
hack.__ptr = (unsigned char *)buff;
hack.__ocnt = n == 0 ? 0 : n-1;
length = __vfprintf(&hack, fmt, a, fp_display, 0);
if (n != 0) *hack.__ptr = 0;
va_end(a);
return(length);
}
int vfprintf(FILE *p, const char *fmt, va_list args)
{
return __vfprintf(p, fmt, args, fp_display, 0);
......@@ -573,5 +677,22 @@ int vsprintf(char *buff, const char *fmt, va_list a)
return(length);
}
int vsnprintf(char *buff, size_t n, const char *fmt, va_list a)
{
FILE hack;
/*************************************************************************/
/* Note that this code interacts in a dubious way with the putc macro. */
/*************************************************************************/
int length;
memclr(&hack, sizeof(FILE));
hack.__flag = _IOSTRG+_IOWRITE;
hack.__ptr = (unsigned char *)buff;
hack.__ocnt = n == 0 ? 0 : n-1;
length = __vfprintf(&hack, fmt, a, fp_display, 0);
if (n != 0) *hack.__ptr = 0;
return(length);
}
/* End of fpprintf.c */
......@@ -46,94 +46,10 @@
#include <math.h> /* for forward references */
#ifdef IBMFLOAT
const double __huge_val = 7.2370055773322621e+75;
#else
/* On the ARM, this has moved into the library's static data area */
/* so that it still works with the Shared C Library module. */
/* const double __huge_val = 1.79769313486231571e+308; */
#endif
#ifdef IBMFLOAT
double frexp(d, lvn)
double d; int *lvn;
{
fp_number d1;
int n;
if (d==0.0)
/* I worry a little about signed zeros here. I hope that -0.0 == 0.0 */
{ *lvn = 0;
return 0.0;
}
d1.d = d;
n = 4*(d1.i.x - 0x40); /* excess 64 exponent */
d1.i.x = 0x40;
d = d1.d;
/* Note that the following code works for unnormalised numbers, but */
/* can then take 55 cycles to converge instead of usual 3 max. */
while ((d>=0 ? d : -d) < 0.5) d = d+d, n--;
/* Now d is most definitely normalised. */
*lvn = n;
return d;
}
double ldexp(d, n)
double d; int n;
{
fp_number d1;
int nx;
if (d==0.0) return 0.0; /* special case */
d1.d = d;
nx = d1.i.x + (n & ~3)/4;
n &= 3;
#ifndef DO_NOT_SUPPORT_UNNORMALIZED_NUMBERS
/* The following code gets the msd/expt right for unnormalised nos. */
d1.i.x = 0x40;
d1.d += 0.0; /* i.e. normalise */
nx += d1.i.x - 0x40;
#endif
{ int mhi = d1.i.mhi;
int nx1 = (mhi & 0x00c00000)==0 ?
((mhi & 0x00200000)==0 ? n - 3 : n - 2) :
((mhi & 0x00800000)==0 ? n - 1 : n);
if (nx1 > 0) nx++, n -= 4;
/* That just dealt with the fact that in IBM format the exponent is for */
/* base 16 and so scaling by a power of two can involve a real multiply. */
/* I now know what the true exponent (nx) in the result will be. */
}
if (nx > 0x7f) /* Overflow (maybe do a raise() ?) */
{ d1.i.x = 0x7f;
d1.i.mhi = 0xffffff;
d1.i.mlo = 0xffffffff;
return d1.d;
}
if (nx < 0) /* Deal with underflow/unnormalised */
{ if (nx <= -14) return 0.0;
d1.i.x = 0;
while (nx < 0) d1.d /= 16, nx++; /* de-normalise gracefully */
}
d1.i.x = nx;
{ double d2;
switch (n)
{
case -3:d2 = 0.125; break;
case -2:d2 = 0.25; break;
case -1:d2 = 0.5; break;
default: /* avoid dataflow whinge */
case 0: d2 = 1.0; break;
case 1: d2 = 2.0; break;
case 2: d2 = 4.0; break;
case 3: d2 = 8.0; break;
}
d1.d *= d2;
}
return d1.d;
}
#else /* Here is the IEEE format stuff */
#ifndef DO_NOT_SUPPORT_UNNORMALIZED_NUMBERS
......@@ -210,14 +126,9 @@ double d; int n;
return (d1.d);
}
#endif
#ifdef IBMFLOAT
#define _exp_arg_limit 174.673089501106208
#else
#define _exp_arg_limit 709.78271289338397
#endif
/* machine independent code - but beware the 1e-20's */
......@@ -291,14 +202,10 @@ double cos(double x)
else return _sincos(x, _pi_2 + x, 1, 1);
}
#ifdef IBMFLOAT
#define _exp_negative_arg_limit -180.218266945585778
#else
/* NB: the following value is a proper limit provided denormalised */
/* values are not being supported. It would need to be changed if they */
/* were to start existing. */
#define _exp_negative_arg_limit -708.39641853226408
#endif
double exp(double x)
{
......@@ -313,14 +220,7 @@ double exp(double x)
/* In C the cast (int)x truncates towards zero. Here I want to round. */
n = (int)((x >= 0 ? 0.5 : -0.5) + 1.44266950408889634074 * x);
xn = (double)n;
#ifdef IBMFLOAT
{ double x1 = (double)(int)x;
double x2 = x - x1;
g = ((x1 - xn * 0.693359375) + x2) - xn * (-2.1219444005469058277e-4);
}
#else
g = (x - xn * 0.693359375) - xn * (-2.1219444005469058277e-4);
#endif
z = g * g;
#define _exp_p0 0.249999999999999993
#define _exp_p1 0.694360001511792852e-2
......@@ -387,34 +287,17 @@ double sqrt(double x)
return -HUGE_VAL;
}
f.d = x;
#ifdef IBMFLOAT
n = f.i.x - 0x40;
f.i.x = 0x40;
#else
n = f.i.x - 0x3fe;
f.i.x = 0x3fe;
#endif
{ double fd = f.d;
#ifdef IBMFLOAT
y0 = 0.223607 + 0.894427 * fd;
#else
y0 = 0.41731 + 0.59016 * fd;
#endif
y0 = 0.5 * (y0 + fd/y0);
y0 = 0.5 * (y0 + fd/y0);
y0 = 0.5 * (y0 + fd/y0);
#ifdef IBMFLOAT
#define __EPS 2.2204460492503131e-16
y0 = y0 + (0.5 * (fd/y0 - y0) + __EPS/32.0);
#endif
}
if (n & 1)
{
#ifdef IBMFLOAT
y0 = (y0 + __EPS/8.0) * 0.25;
#else
y0 *= _sqrt_half;
#endif
n += 1;
}
n /= 2;
......@@ -435,14 +318,7 @@ double _tancot(double x, int iflag)
n = (int) ((2.0 * y + _pi_2) / _pi_);
if (x < 0) n = - n;
xn = (double) n;
#ifdef IBMFLOAT
{ double x1 = (double)(int)x;
double x2 = x - x1;
f = ((x1 - xn*1.57080078125) + x2) + xn*4.454455103380768678308e-6;
}
#else
f = (x - xn*1.57080078125) + xn*4.454455103380768678308e-6;
#endif
if (fabs(f) > 1.e-10)
{ g = f * f;
#define _tan_p1 -0.13338350006421960681
......@@ -591,39 +467,6 @@ double pow(double x, double y)
/* The table a1[] contains properly rounded values for 2**(i/16), and */
/* a2[] contains differences between the true values of 2**(i/16) and */
/* the a1[] values for odd i. */
#ifdef IBMFLOAT
const static double a1[17] = {
/* It is painfully important that the following 17 floating point */
/* numbers are read in to yield the quantities shown on the right. */
1.000000000000000000, /* 41100000:00000000 */
0.957603280698573644, /* 40f5257d:152486cc */
0.917004043204671229, /* 40eac0c6:e7dd2439 */
0.878126080186649740, /* 40e0ccde:ec2a94e1 */
0.840896415253714543, /* 40d744fc:cad69d6b */
0.805245165974627155, /* 40ce248c:151f8481 */
0.771105412703970413, /* 40c5672a:115506db */
0.738413072969749659, /* 40bd08a3:9f580c37 */
0.707106781186547531, /* 40b504f3:33f9de65 */
0.677127773468446367, /* 40ad583e:ea42a14b */
0.648419777325504834, /* 40a5fed6:a9b15139 */
0.620928906036742028, /* 409ef532:6091a112 */
0.594603557501360527, /* 409837f0:518db8a9 */
0.569394317378345823, /* 4091c3d3:73ab11c3 */
0.545253866332628830, /* 408b95c1:e3ea8bd7 */
0.522136891213706919, /* 4085aac3:67cc487b */
0.500000000000000000 /* 40800000:00000000 */
};
const static double a2[8] = {
2.4114209503420287e-18,
9.2291566937243078e-19,
-1.5241915231122319e-18,
-3.5421849765286817e-18,
-3.1286215245415074e-18,
-4.4654376565694489e-18,
2.9305146686217562e-18,
1.1260851040933474e-18
};
#else /* IEEE format */
const static double a1[17] = {
/* It is painfully important that the following 17 floating point */
/* numbers are read in to yield the quantities shown on the right. */
......@@ -655,7 +498,6 @@ double pow(double x, double y)
4.4563878092065126e-17,
4.2759448527536718e-17
};
#endif
if (y == 1.0) return x;
if (x <= 0.0)
{ int ny;
......@@ -709,11 +551,7 @@ double pow(double x, double y)
w2 = w2 - w;
/* The following values have been determined experimentally, buth their */
/* values are not very critical. */
#ifdef IBMFLOAT
# define _negative_pow_limit -4160
#else
# define _negative_pow_limit -16352
#endif
if (iw1 < _negative_pow_limit)
{ errno = ERANGE; /* Underflow certain */
return 0.0;
......@@ -738,17 +576,6 @@ double pow(double x, double y)
z = a1[pdash] + a1[pdash]*z;
z = frexp(z, &m);
mdash += m;
#ifdef IBMFLOAT
if (mdash > 0x3f*4)
{ errno = ERANGE;
if (sign) r = -HUGE_VAL;
else r = HUGE_VAL;
}
else if (mdash <= -0x41*4)
{ errno = ERANGE;
r = 0.0;
}
#else
if (mdash >= 0x7ff-0x3fe)
{ errno = ERANGE;
if (sign) r = -HUGE_VAL;
......@@ -758,7 +585,6 @@ double pow(double x, double y)
{ errno = ERANGE;
r = 0.0;
}
#endif
else
{ r = ldexp(z, mdash);
if (sign) r = -r;
......@@ -789,14 +615,74 @@ double atan2(double y, double x)
return y;
}
#undef fabs
double hypot(double x, double y)
{
double p, q, r, s;
/* Use the Moler-Morrison algorithm */
p = fabs(x);
q = fabs(y);
/* Ensure p <= q (putting NaNs in p and Infs in q). p!=p is a
* simple NaN check without the function call overhead of isnan()
* [it has the nicety of not trapping signalling NaNs, which we don't
* need]. If we can avoid calling any functions, we save a lot of
* overhead.
*/
if (isgreater(p,q) || isunordered(p,q) && p!=p)
{
r = p; p = q; q = r;
}
if (p == 0.0 || q == INFINITY) return q;
if (p != p) return p;
for (;;)
{
r = q / p;
r = r * r;
s = r + 4.0;
/* The compiler is capable of optimising multiple comparisons */
if (s == 4.0 || isunordered(s, 4.0)) return p;
r = r / s;
p = p + 2.0 * r * p;
q = q * r;
}
}
double fabs(double x)
/* All over again, in floats */
float hypotf(float x, float y)
{
if (x<0.0) return -x;
else return x;
float p, q, r, s;
p = fabsf(x);
q = fabsf(y);
if (isgreater(p,q) || isunordered(p,q) && p!=p)
{
r = p; p = q; q = r;
}
if (p == 0.0F || q == INFINITY) return q;
if (p != p) return p;
for (;;)
{
r = q / p;
r = r * r;
s = r + 4.0F;
if (s == 4.0F || isunordered(s, 4.0F)) return p;
r = r / s;
p = p + 2.0F * r * p;
q = q * r;
}
}
/* Use the macros, which expand to inline ABS instructions */
double (fabs)(double x) { return fabs(x); }
float (fabsf)(float x) { return fabsf(x); }
double sinh(double x)
{
int sign;
......@@ -923,95 +809,6 @@ double fmod(double x, double y)
return r;
}
#ifdef IBMFLOAT
double floor(double d)
{
/* round x down to an integer towards minus infinity. */
fp_number x;
int exponent, mask, exact;
if (d == 0.0) return 0.0;
x.d = d; /* pun on union type */
if ((exponent = x.i.x - 0x40) < 0)
{ if (x.i.s) return -1.0;
else return 0.0;
}
else if (exponent >= 56/4) return x.d;
if (exponent >= 24/4)
{ mask = ((unsigned) 0xffffffff) >> (4*(exponent - 24));
exact = x.i.mlo & mask;
x.i.mlo &= ~mask;
}
else
{ mask = 0xfffff >> (4*exponent);
exact = (x.i.mhi & mask) | x.i.mlo;
x.i.mhi &= ~mask;
x.i.mlo = 0;
}
if (exact!=0 && x.i.s) return x.d - 1.0;
else return x.d;
}
double ceil(double d)
{
/* round x up to an integer towards plus infinity. */
fp_number x;
int exponent, mask, exact;
if (d == 0.0) return 0.0;
x.d = d; /* pun on union type */
if ((exponent = x.i.x - 0x40) < 0)
{ if (x.i.s) return 0.0;
else return 1.0;
}
else if (exponent >= 56/4) return x.d;
if (exponent >= 24/4)
{ mask = ((unsigned) 0xffffffff) >> (4*(exponent - 24));
exact = x.i.mlo & mask;
x.i.mlo &= ~mask;
}
else
{ mask = 0xfffff >> (4*exponent);
exact = (x.i.mhi & mask) | x.i.mlo;
x.i.mhi &= ~mask;
x.i.mlo = 0;
}
if (exact!=0 && x.i.s==0) return x.d + 1.0;
else return x.d;
}
double modf(double value, double *iptr)
{
/* splits value into integral part & fraction (both same sign) */
fp_number x;
int exponent, mask;
if (value == 0.0)
{ *iptr = 0.0;
return 0.0;
}
x.d = value;
if ((exponent = x.i.x - 0x40) < 0)
{ *iptr = 0.0;
return value;
}
else if (exponent >= 56/4)
{ *iptr = value;
return 0.0;
}
if (exponent >= 24/4)
{ mask = ((unsigned) 0xffffffff) >> (4*(exponent - 24));
x.i.mlo &= ~mask;
}
else
{ mask = 0xffffff >> (4*exponent);
x.i.mhi &= ~mask;
x.i.mlo = 0;
}
*iptr = x.d;
return value - x.d;
}
#else /* IBMFLOAT */
double floor(double d)
{
/* round x down to an integer towards minus infinity. */
......@@ -1097,7 +894,32 @@ double modf(double value, double *iptr)
return value - x.d;
}
#endif /* IBMFLOAT */
double nan(const char *s)
{
return (double) NAN;
}
float nanf(const char *s)
{
return NAN;
}
double fdim(double x, double y)
{
if (islessequal(x, y))
return 0.0;
else
return x - y; /* Will return NaN for NaN input */
}
float fdimf(float x, float y)
{
if (islessequal(x, y))
return 0.0F;
else
return x - y; /* Will return NaN for NaN input */
}
#endif /* NO_FLOATING_POINT */
/* end of math.c */
......@@ -50,6 +50,7 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
int _fprintf(FILE *fp, const char *fmt, ...);
int _printf(const char *fmt, ...);
int _sprintf(char *buff, const char *fmt, ...);
int _snprintf(char *buff, size_t n, const char *fmt, ...);
int _vfprintf(FILE *p, const char *fmt, va_list args);
int _vsprintf(char *buff, const char *fmt, va_list a);
......@@ -73,6 +74,7 @@ int _sprintf_lf(char *buff, const char *fmt, ...);
#define _SHORTSPEC 0100
#define _PADZERO 0200 /* *** DEPRECATED FEATURE *** */
#define _FPCONV 0400
#define _CHARSPEC 01000
#endif /* _LJUSTIFY */
......@@ -128,9 +130,10 @@ static int printf_display(FILE *p, int flags, int ch, int precision, int width,
break;
#ifndef NO_FLOATING_POINT
case 'f':
case 'f': case 'F':
case 'g': case 'G':
case 'e': case 'E':
case 'a': case 'A':
len = fp_display_fn(ch, d, buff, flags,
/* The following arguments are set by fp_display_fn */
&prefix, &precision,
......@@ -290,11 +293,17 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
}
if (t >= 0) flags |= _PRECGIVEN, precision = t;
}
if (ch=='l' || ch=='L')
if (ch=='l' || ch=='L' || ch=='j' || ch=='z' || ch=='t')
/* 'l' Indicate that a numeric argument is 'long'. Here int and long */
/* are the same (32 bits) and so I can ignore this flag! */
/* 'L' Marks floating arguments as being of type long double. Here this */
/* is the same as just double, and so I can ignore the flag. */
/* 'j' Indicates that a numeric argument is 'intmax_t', or that a %n */
/* argument is a pointer to an intmax_t. We can ignore it. */
/* 'z' Indicates that a numeric argument is 'size_t', or that a %n */
/* argument is a pointer to a size_t. We can ignore it. */
/* 't' Indicates that a numeric argument is 'ptrdiff_t', or that a %n */
/* argument is a pointer to a ptrdiff_t. We can ignore it. */
{ flags |= _LONGSPECIFIER;
ch = *fmt++;
}
......@@ -302,6 +311,10 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
/* 'h' Indicates that an integer value is to be treated as short. */
{ flags |= _SHORTSPEC;
ch = *fmt++;
if (ch=='h')
{ flags |= _CHARSPEC;
ch = *fmt++;
}
}
/* Now the options have been decoded - I can process the main dispatch */
......@@ -364,6 +377,7 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
/* octal and decimal output via %o and %d. */
case 'X': v = va_arg(args, int);
if (flags & _SHORTSPEC) v = (unsigned short)v;
if (flags & _CHARSPEC) v = (unsigned char)v;
hextab = "0123456789ABCDEF";
prefix = ((flags&_VARIANT) != 0 && v != 0)? "0X" : "";
if (flags & _PRECGIVEN) flags &= ~_PADZERO;
......@@ -371,6 +385,7 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
case 'x': v = va_arg(args, int);
if (flags & _SHORTSPEC) v = (unsigned short)v;
if (flags & _CHARSPEC) v = (unsigned char)v;
hextab = "0123456789abcdef";
prefix = ((flags&_VARIANT) != 0 && v != 0)? "0x" : "";
if (flags & _PRECGIVEN) flags &= ~_PADZERO;
......@@ -387,12 +402,14 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
case 'o': v = va_arg(args, int);
if (flags & _SHORTSPEC) v = (unsigned short)v;
if (flags & _CHARSPEC) v = (unsigned char)v;
prefix = (flags&_VARIANT) ? "0" : "";
if (flags & _PRECGIVEN) flags &= ~_PADZERO;
break;
case 'u': v = va_arg(args, unsigned int);
if (flags & _SHORTSPEC) v = (unsigned short)v;
if (flags & _CHARSPEC) v = (unsigned char)v;
prefix = "";
if (flags & _PRECGIVEN) flags &= ~_PADZERO;
break;
......@@ -400,6 +417,7 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
case 'i':
case 'd': { int w = va_arg(args, int);
if (flags & _SHORTSPEC) w = (signed short)w;
if (flags & _CHARSPEC) w = (signed char)w;
if (w<0) v = 0U-w, prefix = "-";
else
v = w, prefix = (flags&_SIGNED) ? "+" :
......@@ -409,10 +427,13 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
break;
case 'f':
case 'F':
case 'e':
case 'E':
case 'g':
case 'G': flags |= _FPCONV;
case 'G':
case 'a':
case 'A': flags |= _FPCONV;
if (!(flags & _PRECGIVEN)) precision = 6;
#ifndef NO_FLOATING_POINT
d = va_arg(args, double);
......@@ -425,8 +446,8 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
{ int w = va_arg(args, int);
w = va_arg(args, int);
/* If the pre-processor symbol FLOATING_POINT is not set I assume that */
/* floating point is not available, and so support %e, %f and %g with */
/* a fragment of code that skips over the relevant argument. */
/* floating point is not available, and so support %e, %f, %g and %a */
/* with a fragment of code that skips over the relevant argument. */
/* I also assume that a double takes two int-sized arg positions. */
prefix = (flags&_SIGNED) ? "+" :
(flags&_BLANKER) ? " " : "";
......@@ -440,7 +461,7 @@ int __vfprintf(FILE *p, const char *fmt, va_list args,
continue;
}
}
return ferror(p) ? EOF : charcount;
return ferror(p) && !(p->__flag & _IOSTRG) ? EOF : charcount;
}
static int no_fp_display(int ch, double *d, char buff[], int flags,
......@@ -509,6 +530,25 @@ int _sprintf(char *buff, const char *fmt, ...)
return(length);
}
int _snprintf(char *buff, size_t n, const char *fmt, ...)
{
FILE hack;
va_list a;
/*************************************************************************/
/* Note that this code interacts in a dubious way with the putc macro. */
/*************************************************************************/
int length;
va_start(a, fmt);
memclr(&hack, sizeof(FILE));
hack.__flag = _IOSTRG+_IOWRITE;
hack.__ptr = (unsigned char *)buff;
hack.__ocnt = n == 0 ? 0 : n-1;
length = __vfprintf(&hack, fmt, a, no_fp_display, 0);
if (n != 0) *hack.__ptr = 0;
va_end(a);
return(length);
}
int _sprintf_lf(char *buff, const char *fmt, ...)
{
FILE hack;
......
......@@ -40,6 +40,7 @@
#include <stddef.h>
#include <stdarg.h>
#include <limits.h>
#include <fenv.h>
/* HIDDEN IMPORT from stdio.c */
extern int __backspace(FILE *stream); /* a strict R-inverse of getc() */
......@@ -54,6 +55,7 @@ extern int __backspace(FILE *stream); /* a strict R-inverse of getc() */
#define NEGEXP 0200 /* internal to rd_real */
#define NUMOK 0400 /* ditto + rd_int */
#define NUMNEG 01000 /* ditto + rd_int */
#define CHAR 02000
#define countgetc(p) (charcount++, getc(p))
......@@ -62,6 +64,7 @@ extern int __backspace(FILE *stream); /* a strict R-inverse of getc() */
/* test for LONG and SHORT properly, but not general extra code. */
#define isLONG_(flag) ((flag) & LONG && sizeof(int) != sizeof(long))
#define isSHORT_(flag) ((flag) & SHORT)
#define isCHAR_(flag) ((flag) & CHAR)
#define isLONGDOUBLE_(flag) \
((flag) & LONGDOUBLE && sizeof(double) != sizeof(long double))
......@@ -131,13 +134,15 @@ case '+': ch = countgetc(p);
if (flag & ALLOWSIGN)
{ long int m = flag & NUMNEG ? -n : n;
int *p = va_arg(res, int *); /* rely on sizeof(int*)=sizeof(short*) */
if isSHORT_(flag) *(short *)p = (short)m;
if isCHAR_(flag) *(signed char *)p = (signed char)m;
else if isSHORT_(flag) *(short *)p = (short)m;
else if isLONG_(flag) *(long *)p = m;
else *(int *)p = (int)m;
}
else /* pointer case comes here too - with quite some type pun! */
{ unsigned int *p = va_arg(res, unsigned int *);
/* rely on sizeof(unsigned int *)==sizeof(unsigned short *) */
if isCHAR_(flag) *(unsigned char *)p = (unsigned char)n;
if isSHORT_(flag) *(unsigned short *)p = (unsigned short)n;
else if isLONG_(flag) *(unsigned long *)p = n;
else *(unsigned int *)p = (unsigned int)n;
......@@ -148,50 +153,182 @@ case '+': ch = countgetc(p);
#ifndef NO_FLOATING_POINT
#ifdef IBMFLOAT
static float carefully_narrow(double l)
{
/* Maybe in scanf I should ROUND rather than TRUNCATE here... */
static const int amax = 0x7fffffff, amin = 0xffffffff;
if (l >= (double)*(float *)&amax ||
l <= (double)*(float *)&amin) return (float)l;
else /* above line avoids overflow */
{ float f = (float) l; /* narrower version */
double lost = l - (double)f; /* amount that was chopped off */
return (float)(l + +(lost + lost));
}
}
#else /* IBMFLOAT */
static float carefully_narrow(double l)
/* All the trouble I went to to detect potential overflow has to be re- */
/* done here so that underflow and overflow do not occur during the */
/* narrowing operation that is about to be done. */
/* *********** machine dependent code ************* (should not go here) */
{ int w;
(void)frexp(l, &w); /* extract exponent */
w = w + 0x7e; /* exponent for single precision version */
if (w<=0 && l!=0.0)
{ errno = ERANGE;
return 0.0f;
#pragma STDC FENV_ACCESS ON
fenv_t env;
float f;
feholdexcept(&env);
f = (float) l;
if (fetestexcept(FE_UNDERFLOW|FE_OVERFLOW))
errno = ERANGE;
fesetenv(&env);
return f;
}
/* Do the conversion work from hex to a double/float.
* a[] is up to 19 hex digits, fed in at the bottom.
* x is the exponent so far. Assumes non-zero input.
*/
static double cvthex(unsigned *a, int x, int flag)
{
unsigned round, sticky;
unsigned msb, lsw;
int minx, maxx;
/* Note parameters of the destination type */
if (flag & LONG)
msb = 0x00100000, lsw = 1, minx = -1022, maxx=1023, x += 20 + 64;
else
msb = 0x00800000, lsw = 0, minx = -126, maxx=127, x += 23 + 64;
/* Normalise the input digits */
if (a[0]==0 && a[1]==0)
{ a[1] = a[2];
a[2] = 0;
x -= 32;
}
while ((a[0] & msb)==0)
{ a[0] = (a[0]<<1) | (a[1]>>31);
a[1] = (a[1]<<1) | (a[2]>>31);
a[2] = a[2]<<1;
x -= 1;
}
/* Check for total underflow */
if (x < minx - 64)
{ errno = ERANGE;
return 0.0;
}
/* Denormalise if necessary */
if (x < minx)
{ do
{ a[2] = (a[1]<<31) | (a[2]>>1) | (a[2]&1);
a[1] = (a[0]<<31) | (a[1]>>1);
a[0] = (a[0]>>1);
} while (++x < minx);
x = minx - 1;
}
/* Proceed to round */
round = a[lsw+1] >> 31;
sticky = a[lsw+1] & 0x7fffffff;
if (lsw == 0)
sticky |= a[2];
/* Round up if necessary */
if (round)
{ if (sticky || (a[lsw] & 1))
{ if (++a[lsw] == 0)
a[0]++;
/* Renormalise if necessary */
if (a[0] & (msb<<1))
{ a[1] = (a[0]<<31) | (a[1]>>1);
a[0] = (a[0]>>1);
x += 1;
}
/* or convert denormalised to normalised */
else if (x < minx && (a[0] & msb)) /* x will be minx-1 */
{ x = minx;
errno = ERANGE;
}
}
else if (w >= 0xff)
/* Overflow of single-precision values - fudge single precision infinity */
/* *********** machine dependent code ************* (should not go here) */
{ static int posinf = 0x7f800000, neginf = 0xff800000;
errno = ERANGE;
return *(float *)(l >= 0.0 ? &posinf : &neginf);
}
/* Indicate underflow (denormalised, and inaccurate - really should only
* report underflow if inaccuracy DUE TO DENORMALISATION, but hey) */
if (x < minx && (round || sticky))
errno = ERANGE;
/* Check for overflow */
if (x > maxx)
{ errno = ERANGE;
return (flag & NUMNEG) ? -HUGE_VAL : HUGE_VAL;
}
if (flag & NUMNEG) a[0] |= 0x80000000;
if (flag & LONG)
{ a[0] = (a[0] &~ msb) | ((x+1023) << 20);
return *(double *) a;
}
else
{ a[0] = (a[0] &~ msb) | ((x+127) << 23);
return *(float *) a;
}
}
static double rd_naninf(FILE *p, int ch, int *flagp, int field, long int *charcountp)
{
double l;
long int charcount = *charcountp;
int flag = *flagp;
const char *match = (ch == 'n' || ch == 'N') ? "NAN" : "INFINITY";
const char *m = match;
while (field > 0)
{ if (ch >= 'a' && ch <= 'z') ch += 'A'-'a';
if (ch == *m && *m != '\0') {
ch = countgetc(p);
field--;
}
else return (float)l; /* what we really wanted to do */
else break;
m++;
}
if (*m == '\0' || (match[0] == 'I' && m == match+3))
{
flag |= NUMOK;
if (match[0] == 'N')
{
if (field > 0 && ch == '(')
{
flag &=~ NUMOK;
ch = countgetc(p);
field--;
while (field > 0)
{ if (ch >= 'a' && ch <= 'z' ||
ch >= 'A' && ch <= 'Z' ||
ch >= '0' && ch <= '9' ||
ch == '_')
{ ch = countgetc(p);
field--;
}
else if (ch == ')')
{ ch = countgetc(p);
field--;
flag |= NUMOK;
break;
}
else break;
}
}
l = flag & NUMNEG ? -NAN : NAN;
}
else
l = flag & NUMNEG ? -INFINITY : INFINITY;
}
#endif /* IEEE */
else
l = HUGE_VAL;
__backspace(p);
*charcountp = charcount;
*flagp = flag;
return l;
}
#ifdef HOST_HAS_BCD_FLT
static long int rd_real(FILE *p, va_list res, int flag, int field)
{
long int charcount = -1; /* allow for always ungetc */
int ch, x = 0;
int ch, x = 0, ishex = 0;
unsigned int a[3]; /* IEEE 'packed' format as per ACORN FPE2 */
double l = 0.0;
a[0] = a[1] = a[2] = 0;
......@@ -205,24 +342,45 @@ case '+': ch = countgetc(p);
field--;
break;
}
if (field > 0 && (ch == 'n' || ch == 'N' || ch == 'i' || ch == 'I'))
{ l = rd_naninf(p, ch, &flag, field, &charcount);
goto lready;
}
if (field >= 2 && ch == '0')
{ ch = countgetc(p);
field--;
if (ch == 'x' || ch == 'X')
{ ch = countgetc(p);
field--;
ishex = 1;
}
else
/* We've swallowed the 0. No-one will care if we do this: */
flag |= NUMOK;
}
while (field > 0)
{ if ((ch==*decimal_point || ch=='.') && !(flag & DOTSEEN))
flag |= DOTSEEN, field--;
else if (isdigit(ch))
else if (isdigit(ch) || ishex && isxdigit(ch))
{ flag |= NUMOK, field--;
if ((a[0] & 0xf00) == 0)
{ a[0] = (a[0]<<4) | (a[1]>>28);
a[1] = (a[1]<<4) | (a[2]>>28);
a[2] = (a[2]<<4) | scanf_intofdigit(ch);
a[2] = (a[2]<<4) | (ishex ? ch_val(ch, 16) : scanf_intofdigit(ch));
if (flag & DOTSEEN) x -= 1;
}
else if (!(flag & DOTSEEN)) x += 1;
else
{ if (ishex && ch != '0') a[2] |= 1;
if (!(flag & DOTSEEN)) x += 1;
}
}
else break;
ch = countgetc(p);
}
if (ishex) x *= 4;
/* we must unread the 'e' in (say) "+.e" as cannot be valid */
if (field > 0 && (ch == 'e' || ch == 'E') && (flag & NUMOK))
if (field > 0 && (ishex && (ch == 'p' || ch == 'P') ||
!ishex && (ch == 'e' || ch == 'E')) && (flag & NUMOK))
{ int x2 = 0;
flag &= ~(NUMOK+NEGEXP), field--;
switch (ch = countgetc(p))
......@@ -240,7 +398,8 @@ case '+': ch = countgetc(p);
if (flag & NEGEXP) x -= x2; else x += x2;
}
__backspace(p);
if (a[0]==0 && a[1]==0 && a[2]==0) l = 0.0;
if (a[0]==0 && a[1]==0 && a[2]==0) l = (flag & NUMNEG) ? -0.0 : 0.0;
else if (ishex) l = cvthex(a, x, flag);
else
{ if (a[0]==0 && a[1]==0)
{ a[1] = a[2];
......@@ -274,6 +433,7 @@ case '+': ch = countgetc(p);
l = _ldfp(a); /* sets errno if necessary */
}
}
lready:
if (!(flag & NUMOK)) return CVTFAIL;
if (flag & LONG)
{ if (!(flag & NOSTORE))
......@@ -489,8 +649,7 @@ static long int rd_string_map(FILE *p, va_list res, int flag, int field,
return charcount;
}
/* It seems amazing that vfscanf is not available externally in ANSI */
static int vfscanf(FILE *p, const char *sfmt, va_list argv)
int vfscanf(FILE *p, const char *sfmt, va_list argv)
{
/* The next line is essential (see isspace() ANSI doc. and also use of
* charmap[] below) if char is signed by default.
......@@ -542,7 +701,11 @@ case '%': { int field = 0, flag = 0;
if (!(flag & FIELDGIVEN)) field = INT_MAX;
if (fch == 'l') fch = *fmt++, flag |= LONG;
else if (fch == 'L') fch = *fmt++, flag |= LONG | LONGDOUBLE;
else if (fch == 'h') fch = *fmt++, flag |= SHORT;
else if (fch == 'h')
{ fch = *fmt++, flag |= SHORT;
if (fch == 'h') fch = *fmt++, flag |= CHAR;
}
else if (fch == 'j' || fch == 'z' || fch == 't') fch = *fmt++;
switch (fch)
{
default: return cnt; /* illegal conversion code */
......@@ -576,8 +739,11 @@ case '%': { int field = 0, flag = 0;
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
case 'a':
case 'A':
#ifndef NO_FLOATING_POINT
worked = rd_real(p, argv, flag, field);
#else
......@@ -589,14 +755,15 @@ case '%': { int field = 0, flag = 0;
/* %n assigns the number of characters read from the input so far - NOTE */
/* that this assignment is NOT influenced by the * flag and does NOT */
/* count towards the value returned by scanf. Note that h and l apply. */
case 'n': if isSHORT_(flag) *va_arg(argv, short *) = (short)charcount;
case 'n': if isCHAR_(flag) *va_arg(argv, char *) = (char)charcount;
else if isSHORT_(flag) *va_arg(argv, short *) = (short)charcount;
else if isLONG_(flag) *va_arg(argv, long *) = charcount;
else *va_arg(argv, int *) = (int)charcount;
continue;
case 'o': worked = rd_int(p, argv, flag | ALLOWSIGN, 8, field);
break;
/* pointers are displayed in hex, but h,l,L ignored */
case 'p': worked = rd_int(p, argv, flag & ~(LONG|SHORT), 16, field);
case 'p': worked = rd_int(p, argv, flag & ~(LONG|SHORT|CHAR), 16, field);
break;
case 's': worked = rd_string(p, argv, flag, field);
break;
......@@ -648,6 +815,11 @@ int scanf(const char *fmt, ...)
return n;
}
int vscanf(const char *fmt, va_list a)
{
return vfscanf(stdin, fmt, a);
}
typedef struct __extradata {
/*
* BODGE BODGE BODGE BODGE
......@@ -661,19 +833,17 @@ typedef struct __extradata {
int __f;
} _extradata, *_extradatap;
int sscanf(const char *buff, const char *fmt, ...)
int vsscanf(const char *buff, const char *fmt, va_list a)
{
/*************************************************************************/
/* Note that this code interacts in a dubious way with the getc macro. */
/* Also ungetc. */
/*************************************************************************/
va_list a;
FILE hack;
_extradata extra;
_extradatap extrap = &extra;
int n;
va_start(a, fmt);
memclr(&hack, sizeof(FILE));
memclr(extrap, sizeof(_extradata));
hack.__flag = _IOSTRG+_IOREAD;
......@@ -681,6 +851,15 @@ int sscanf(const char *buff, const char *fmt, ...)
hack.__icnt = strlen(buff);
hack.__extrap = extrap;
n = vfscanf(&hack, fmt, a);
return n;
}
int sscanf(const char *buff, const char *fmt, ...)
{
va_list a;
int n;
va_start(a, fmt);
n = vsscanf(buff, fmt, a);
va_end(a);
return n;
}
......
......@@ -26,6 +26,8 @@
/* mblen, mbtowc, wctomb, mbstowcs, wcstombs are implemented in locale.c */
/* div and ldiv are implemented in machine code */
static unsigned long int next = 1;
int _ANSI_rand() /* This is the ANSI suggested portable code */
......@@ -170,25 +172,5 @@ long int labs(long int x)
else return x;
}
div_t div(int numer, int denom)
{
/* This is a candidate for re-implementation in machine code so that the */
/* quotient and remainder can be computed all at once. However I am not */
/* really convinced about the importance of the function so will not do */
/* that yet! */
div_t res;
res.quot = numer / denom;
res.rem = numer % denom;
return res;
}
ldiv_t ldiv(long int numer, long int denom)
{
ldiv_t res;
res.quot = numer / denom;
res.rem = numer % denom;
return res;
}
/* end of stdlib.c */
/* Copyright 2002 Pace Micro Technology plc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma force_top_level
#pragma include_only_once
/* fenv.h: ISO 'C' (9899:1999) library header, section 7.6 */
/* Copyright (C) Acorn Computers Ltd. 2002 */
/* version 1.00 */
#ifndef __fenv_h
#define __fenv_h
typedef unsigned int fexcept_t;
/* represents the floating-point status flags collectively */
typedef struct fenv_t
{ unsigned status;
unsigned reserved[5];
} fenv_t;
/* represents the entire floating-point environment */
#define FE_INVALID 0x01
#define FE_DIVBYZERO 0x02
#define FE_OVERFLOW 0x04
#define FE_UNDERFLOW 0x08
#define FE_INEXACT 0x10
#define FE_ALL_EXCEPT 0x1F
/* represent floating-point exceptions */
#define FE_TONEAREST 0
/* our only supported rounding direction */
#define FE_DFL_ENV ((const fenv_t *) 0)
/* represents the default floating-point environment - the one installed */
/* at program startup. It can be used as an argument to <fenv.h> */
/* functions that manage the floating point environment. */
#ifdef __cplusplus
extern "C" {
#endif
int feclearexcept(int excepts);
/* attempts to clear the supported floating-point exceptions represented */
/* by its argument. */
/* Returns: zero if the excepts argument is zero or if all the specified */
/* exceptions were successfully cleared. Otherwise, it returns */
/* a nonzero value. */
int fegetexceptflag(fexcept_t *flagp, int excepts);
/* attempts to store an implementation-defined representation of the */
/* states of the floating-point status flags indicated by the argument */
/* excepts in the object pointed to by the argument flagp. */
/* Returns: zero if the representation was successfully stored. */
/* Otherwise, it returns a nonzero value. */
int feraiseexcept(int excepts);
/* attempts to raise the supported floating-point exceptions represented */
/* by its argument. The order in which these floating-point exceptions */
/* are raised is unspecified, except as stated in F.7.6. Whether the */
/* feraiseexcept function additionally raises the "inexact" floating- */
/* point exception whenever it raises the "overflow" or "underflow" */
/* floating-point exception is implementation-defined. */
/* Returns: zero if the excepts argument is zero or if all the specified */
/* exceptions were successfully raised. Otherwise, it returns a */
/* nonzero value. */
int fesetexceptflag(const fexcept_t *flagp, int excepts);
/* attempts to set the floating-point status flags indicated by the */
/* argument excepts to the states stored in the object pointed to by */
/* flagp. The value of *flagp shall have been set by a previous call to */
/* fegetexceptflag whose second argument represented at least those */
/* floating-point exceptions represented by the argument excepts. This */
/* function does not raise floating-point exceptions, but only sets the */
/* state of the flags. */
/* Returns: zero if the excepts argument is zero or if all the specified */
/* flags were successfully set to the appropriate state. */
/* Otherwise, it returns a nonzero value. */
int fetestexcept(int excepts);
/* determines which of a specified subset of the floating-point */
/* exception flags are currently set. The excepts argument specifies the */
/* floating-point status flags to be queried. */
/* Returns: the value of the bitwise OR of the floating-point exception */
/* macros corresponding to the currently set floating-point */
/* exceptions included in excepts. */
int fegetround(void);
/* gets the current rounding direction. */
/* Returns: the value of the rounding direction macro representing the */
/* current rounding direction or a negative value if there is */
/* no such rounding direction macro or the current rounding */
/* direction is not determinable. */
int fesetround(int round);
/* establishes the rounding direction represented by its argument round. */
/* If the argument is not equal to the value of a rounding direction */
/* macro, the rounding direction is not changed. */
/* Returns: zero if and only if the requested rounding direction was */
/* established. */
int fegetenv(fenv_t *envp);
/* attempts to store the current floating-point environment in the */
/* object pointed to by envp. */
/* Returns: zero if the environment was successfully stored. Otherwise, */
/* it returns a nonzero value. */
int feholdexcept(fenv_t *envp);
/* saves the current floating-point environment in the object pointed to */
/* by envp, clears the floating-point status flags, and then installs a */
/* non-stop (continue on floating-point exceptions) mode for all */
/* floating-point exceptions. */
/* Returns: zero if and only if non-stop floating-point exception */
/* handling was successfully installed. */
int fesetenv(const fenv_t *envp);
/* attempts to establish the floating-point environment represented by */
/* the object pointed to by envp. The argument envp shall point to an */
/* object set by a call to fegetenv or feholdexcept, or equal a */
/* floating-point environment macro. Note that fesetenv merely installs */
/* the state of the floating-point status flags represented through its */
/* argument, and does not raise these floating-point exceptions. */
/* Returns: zero if the environment was successfully established. */
/* Otherwise, it returns a nonzero value. */
int feupdateenv(const fenv_t *envp);
/* attempts to save the currently raised floating-point exceptions in */
/* its automatic storage, install the floating-point environment */
/* represented by the object pointed to by envp, and then raise the */
/* saved floating-point exceptions. The argument envp shall point to an */
/* object set by a call to feholdexcept or fegetenv, or equal a */
/* floating-point environment macro. */
/* Returns: zero if all the actions were successfully carried out. */
/* Otherwise, it returns a nonzero value. */
#ifdef __cplusplus
}
#endif
#endif
/* end of fenv.h */
......@@ -15,17 +15,14 @@
#pragma force_top_level
#pragma include_only_once
/* float.h: ANSI 'C' (X3J11 Oct 88) library header, section 2.2.4.2 */
/* float.h: ISO 'C' (9899 Dec 99) library header, section 5.2.4.2 */
/* Copyright (C) Codemist Ltd, 1988 */
/* Copyright (C) Acorn Computers Ltd. 1991, 1992 */
/* version 2.00 */
/* version 3.00 */
#ifndef __float_h
#define __float_h
/* IEEE version: the following values are taken from the above ANSI draft. */
/* The ACORN FPE (v17) is known not to precisely implement IEEE arithmetic. */
#define FLT_RADIX 2
/* radix of exponent representation */
#define FLT_ROUNDS 1
......@@ -39,14 +36,32 @@
* 3 : towards negative infinity.
* ? : any other is implementation-defined.
*/
#define FLT_EVAL_METHOD 0
/*
* The value of operations with floating operands and values subject to the
* usual arithmetic conversions and of floating constants are evaluated to
* a format whose range and precision may be greater than required by the
* type. The use of evaluation formats is characterised by the value of
* FLT_EVAL_METHOD:
* -1 : indeterminable;
* 0 : evaluate all operations and constants just to the range and
* precision of the type;
* 1 : evaluate operations and constants of type float and double to the
* range of the double type, evaluate long double operations and
* constants to the range and precision of the long double type;
* 2 : evaluate all operations and constants to the range and precision
* of the lang double type;
* ? : all other negative values are implementation defined.
*/
#define FLT_MANT_DIG 24
#define DBL_MANT_DIG 53
#define LDBL_MANT_DIG 53
/* number of base-FLT_RADIX digits in the floating point mantissa */
/* The values that follow are not achieved under Acorn's FPE version 17 */
/* but they should be correct in due course! */
#define DECIMAL_DIG 17
/* number of decimal digits required to hold a floating-point number */
/* accurately. */
#define FLT_DIG 6
#define DBL_DIG 15
......
......@@ -15,7 +15,7 @@
#pragma force_top_level
#pragma include_only_once
/* inttypes.h: ISO 'C' (WG14/N843 Aug 98) library header, section 7.8 */
/* inttypes.h: ISO 'C' (ISO/IEC 9899:1999) library header, section 7.8 */
/* Copyright (C) Element 14 Ltd. 1999 */
/* version 1.00 */
......@@ -105,46 +105,61 @@
#define PRIXMAX "X"
#define PRIXPTR "X"
#define SCNd8 "hhd"
#define SCNd16 "hd"
#define SCNd32 "d"
#define SCNdLEAST8 "hhd"
#define SCNdLEAST16 "hd"
#define SCNdLEAST32 "d"
#define SCNdFAST8 "hhd"
#define SCNdFAST16 "d"
#define SCNdFAST32 "d"
#define SCNdMAX "d"
#define SCNdPTR "d"
#define SCNi8 "hhi"
#define SCNi16 "hi"
#define SCNi32 "i"
#define SCNiLEAST8 "hhi"
#define SCNiLEAST16 "hi"
#define SCNiLEAST32 "i"
#define SCNiFAST8 "hhi"
#define SCNiFAST16 "i"
#define SCNiFAST32 "i"
#define SCNiMAX "i"
#define SCNiPTR "i"
#define SCNo8 "hho"
#define SCNo16 "ho"
#define SCNo32 "o"
#define SCNoLEAST8 "hho"
#define SCNoLEAST16 "ho"
#define SCNoLEAST32 "o"
#define SCNoFAST8 "hho"
#define SCNoFAST16 "o"
#define SCNoFAST32 "o"
#define SCNoMAX "o"
#define SCNoPTR "o"
#define SCNu8 "hhu"
#define SCNu16 "hu"
#define SCNu32 "u"
#define SCNuLEAST8 "hhu"
#define SCNuLEAST16 "hu"
#define SCNuLEAST32 "u"
#define SCNuFAST8 "hhu"
#define SCNuFAST16 "u"
#define SCNuFAST32 "u"
#define SCNuMAX "u"
#define SCNuPTR "u"
#define SCNx8 "hhx"
#define SCNx16 "hx"
#define SCNx32 "x"
#define SCNxLEAST8 "hhx"
#define SCNxLEAST16 "hx"
#define SCNxLEAST32 "x"
#define SCNxFAST8 "hhx"
#define SCNxFAST16 "x"
#define SCNxFAST32 "x"
#define SCNxMAX "x"
......@@ -152,6 +167,33 @@
#endif
/*
* The following are fudged with macros, as we don't have real functions
* for them.
*/
#ifndef __div_t
# define __div_t 1
typedef struct div_t { int quot, rem; } div_t;
#endif
#define imaxdiv_t div_t
#ifdef __cplusplus
extern "C" {
#endif
extern div_t div(int /*numer*/, int /*denom*/);
extern long int strtol(const char * /*nptr*/, char **/*endptr*/, int /*base*/);
extern unsigned long int strtoul(const char * /*nptr*/,
char ** /*endptr*/, int /*base*/);
#ifdef __cplusplus
}
#endif
#define imaxdiv(a,b) div(a,b)
#define strtoimax(a,b,c) ((intmax_t)strtol(a,b,c))
#define strtoumax(a,b,c) ((uintmax_t)strtoul(a,b,c))
#endif
/* end of inttypes.h */
......@@ -18,11 +18,15 @@
/* math.h: ANSI 'C' (X3J11 Oct 88) library header, section 4.5 */
/* Copyright (C) Codemist Ltd. */
/* Copyright (C) Acorn Computers Ltd. 1991 */
/* version 0.02 */
/* version 0.03 */
#ifndef __math_h
#define __math_h
typedef float float_t;
typedef double double_t;
/* most efficient types at least as wide as float and double */
#ifndef HUGE_VAL
# define HUGE_VAL __huge_val
#ifdef __cplusplus
......@@ -33,11 +37,70 @@ extern const double HUGE_VAL;
#endif
#endif
#ifndef HUGE_VALF
# define HUGE_VALF INFINITY
#endif
#define INFINITY 0f_7f800000
/* a constant expression of type float representing positive infinity */
#define NAN 0f_7fc00001
/* a constant expression of type float representing a quiet NaN */
#define FP_ZERO 0
#define FP_SUBNORMAL 1
#define FP_NORMAL 2
#define FP_INFINITY 3
#define FP_NAN 4
/* the mutually exclusive kinds of floating-point values for fpclassify() */
#define MATH_ERRNO 1
#define MATH_ERREXCEPT 2
#define math_errhandling MATH_ERRNO
/* <math.h> functions just set errno - no exceptions are raised */
/*#pragma no_side_effects*/
#ifdef __cplusplus
extern "C" {
#endif
#pragma no_side_effects
#pragma force_fpargs_in_regs
extern int __fpclassifyf(float);
extern int __fpclassifyd(double);
extern int __signbitf(float);
extern int __signbitd(double);
#pragma no_force_fpargs_in_regs
#pragma side_effects
#ifdef __cplusplus
#define __classmacro(fn,r) (sizeof(r) == 4 ? __##fn##f(r) : \
__##fn##d(r))
#else
#define __assertfp(r) ___assert(___typeof(r) == 0x002 ||\
___typeof(r) == 0x202 ||\
___typeof(r) == 0x402, \
"Illegal type used with classification macro")
#define __classmacro(fn,r) (__assertfp(r),\
___typeof(r) == 0x402 ? __##fn##f(r) : \
__##fn##d(r))
#endif
#define fpclassify(r) __classmacro(fpclassify,(r))
/* Returns: the value of the appropriate number classification macro */
#define isfinite(r) (fpclassify(r) <= FP_NORMAL)
/* Returns: a nonzero value if and only if its argument is finite */
#define isinf(r) (fpclassify(r) == FP_INFINITY)
/* Returns: a nonzero value if and only if its argument is infinite */
#define isnan(r) (fpclassify(r) == FP_NAN)
/* Returns: a nonzero value if and only if its argument is a NaN */
#define isnormal(r) (fpclassify(r) == FP_NORMAL)
/* Returns: a nonzero value if and only if its argument is normal */
#define signbit(r) __classmacro(signbit,(r))
/* Returns: a nonzero value if and only if its argument is negative */
extern double acos(double /*x*/);
/* computes the principal value of the arc cosine of x */
/* a domain error occurs for arguments not in the range -1 to 1 */
......@@ -128,6 +191,10 @@ extern double modf(double /*value*/, double * /*iptr*/);
/* as a double in the object pointed to by iptr. */
/* Returns: the signed fractional part of value. */
extern double hypot(double /*x*/, double /*y*/);
/* computes the square root of the sum of the squares of x and y, without */
/* undue overflow or underflow. A ronge error may occur. */
/* Returns: sqrt(x^2 + y^2) */
extern double pow(double /*x*/, double /*y*/);
/* computes x raised to the power of y. A domain error occurs if x is */
/* zero and y is less than or equal to zero, or if x is negative and y */
......@@ -144,6 +211,7 @@ extern double ceil(double /*x*/);
/* computes the smallest integer not less than x. */
/* Returns: the smallest integer not less than x, expressed as a double. */
extern double fabs(double /*x*/);
extern float fabsf(float /*x*/);
/* computes the absolute value of the floating-point number x. */
/* Returns: the absolute value of x. */
extern double floor(double /*d*/);
......@@ -157,7 +225,48 @@ extern double fmod(double /*x*/, double /*y*/);
/* occurs and -HUGE_VAL is returned. */
extern double __d_abs(double);
extern float __r_abs(float);
#define fabs(x) __d_abs(x)
#define fabsf(x) __r_abs(x)
#pragma force_fpargs_in_regs
extern double copysign(double /*x*/, double /*y*/);
extern float copysignf(float /*x*/, float /*y*/);
#pragma no_force_fpargs_in_regs
/* produce a value with the magnitude of x and the sign of y. They */
/* produce a NaN (with the sign of y) if x is a NaN. */
/* Returns: a value with the magnitude of x and the sign of y. */
extern double nan(const char * /*tagp*/);
extern float nanf(const char * /*tagp*/);
/* Returns: a quiet NaN, with content indicated through tagp. */
extern double nextafter(double /*x*/, double /*y*/);
extern float nextafterf(float /*x*/, float /*y*/);
/* Returns: the next representable value in the specified format after */
/* x in the direction of y */
extern double fdim(double /*x*/, double /*y*/);
extern float fdimf(float /*x*/, float /*y*/);
/* determine the positive difference between their arguments: */
/* { x-y if x > y */
/* { +0 if x <= y */
/* A range error may occur. */
/* Returns: the positive difference value. */
extern double fmax(double /*x*/, double /*y*/);
extern float fmaxf(float /*x*/, float /*y*/);
/* Returns: the maximum numeric value of their arguments. */
extern double fmin(double /*x*/, double /*y*/);
extern float fminf(float /*x*/, float /*y*/);
/* Returns: the minimum numeric value of their arguments. */
#define isgreater(x,y) ((x) __greater (y))
#define isgreaterequal(x,y) ((x) __greaterequal (y))
#define isless(x,y) ((x) __less (y))
#define islessequal(x,y) ((x) __lessequal (y))
#define islessgreater(x,y) ((x) __lessgreater (y))
#define isunordered(x,y) ((x) __unordered (y))
/* quiet (non floating-point exception raising) versions of the */
/* relational operators, and other comparison macros that facilitate */
/* writing efficient code that accounts for NaNs without suffering the */
/* "invalid" floating-point exception. */
#ifdef __cplusplus
}
......
......@@ -18,7 +18,7 @@
/* stdio.h: ANSI 'C' (X3J11 Oct 88) library header, section 4.9 */
/* Copyright (C) Codemist Ltd. */
/* Copyright (C) Acorn Computers Ltd., 1990, 1992 */
/* version 2.00 */
/* version 3.00 */
/* AM July-88 changes to all prototypes so that */
/* #define mode 3; #include <stdio.h> can work as ANSI require. */
......@@ -329,6 +329,20 @@ extern int printf(const char * /*format*/, ...);
* Returns: the number of characters transmitted, or a negative value if an
* output error occurred.
*/
extern int snprintf(char * /*s*/, size_t /*n*/, const char * /*format*/, ...);
/*
* is equivalent to fprintf, except that the argument s specifies an array
* into which the generated output is to be written, rather than to a
* stream. If n is zero, nothing is written and s may be a null pointer.
* Otherwise, output characters beyond the n-1st are discarded rather than
* being written to the array, and a null character is written at the end
* of the characters actually written into the array.
* Returns: the number of characters that would have been written had n
* been sufficiently large, not counting the terminating null
* character. Thus, the null-terminated output has been completely
* written if and only if the returned value is nonnegative and
* less than n.
*/
extern int sprintf(char * /*s*/, const char * /*format*/, ...);
/*
* is equivalent to fprintf, except that the argument s specifies an array
......@@ -393,6 +407,28 @@ extern int sscanf(const char * /*s*/, const char * /*format*/, ...);
* even zero, in the event of an early matching failure.
*/
#pragma -v0 /* back to default */
extern int vfprintf(FILE * /*stream*/,
const char * /*format*/, __va_list /*arg*/);
/*
* is equivalent to fprintf, with the variable argument list replaced by
* arg, which has been initialised by the va_start macro (and possibly
* subsequent va_arg calls). The vfprintf function does not invoke the
* va_end function.
* Returns: the number of characters transmitted, or a negative value if an
* output error occurred.
*/
extern int vfscanf(FILE * /*stream*/,
const char * /*format*/, __va_list /*arg*/);
/*
* is equivalent to fscanf, with the variable argument list replaced by
* arg, which has been initialised by the va_start macro (and possibly
* subsequent va_arg calls). The vfscanf function does not invoke the
* va_end function.
* Returns: the value of the macro EOF if an input failure occurs before any
* conversion. Otherwise, the vfscanf function returns the number
* of input items assigned, which can be fewer than provided for,
* or even zero, in the event of an early matching failure.
*/
extern int vprintf(const char * /*format*/, __va_list /*arg*/);
/*
* is equivalent to printf, with the variable argument list replaced by arg,
......@@ -401,15 +437,28 @@ extern int vprintf(const char * /*format*/, __va_list /*arg*/);
* Returns: the number of characters transmitted, or a negative value if an
* output error occurred.
*/
extern int vfprintf(FILE * /*stream*/,
const char * /*format*/, __va_list /*arg*/);
extern int vscanf(const char * /*format*/, __va_list /*arg*/);
/*
* is equivalent to fprintf, with the variable argument list replaced by
* is equivalent to scanf, with the variable argument list replaced by arg,
* which has been initialised by the va_start macro (and possibly subsequent
* va_arg calls). The vscanf function does not invoke the va_end function.
* Returns: the value of the macro EOF if an input failure occurs before any
* conversion. Otherwise, the vscanf function returns the number of
* input items assigned, which can be fewer than provided for, or
* even zero, in the event of an early matching failure.
*/
extern int vsnprintf(char * /*s*/, size_t /*n*/,
const char * /*format*/, __va_list /*arg*/);
/*
* is equivalent to snprintf, with the variable argument list replaced by
* arg, which has been initialised by the va_start macro (and possibly
* subsequent va_arg calls). The vfprintf function does not invoke the
* subsequent va_arg calls). The vsnprintf function does not invoke the
* va_end function.
* Returns: the number of characters transmitted, or a negative value if an
* output error occurred.
* Returns: the number of characters that would have been written had n
* been sufficiently large, not counting the terminating null
* character. Thus, the null-terminated output has been completely
* written if and only if the returned value is nonnegative and
* less than n.
*/
extern int vsprintf(char * /*s*/, const char * /*format*/, __va_list /*arg*/);
/*
......@@ -420,6 +469,17 @@ extern int vsprintf(char * /*s*/, const char * /*format*/, __va_list /*arg*/);
* Returns: the number of characters written in the array, not counting the
* terminating null character.
*/
extern int vsscanf(const char * /*s*/,
const char * /*format*/, __va_list /*arg*/);
/*
* is equivalent to sscanf, with the variable argument list replaced by arg,
* which has been initialised by the va_start macro (and possibly subsequent
* va_arg calls). The sscanf function does not invoke the va_end function.
* Returns: the value of the macro EOF if an input failure occurs before any
* conversion. Otherwise, the vscanf function returns the number of
* input items assigned, which can be fewer than provided for, or
* even zero, in the event of an early matching failure.
*/
extern int fgetc(FILE * /*stream*/);
/*
......
......@@ -42,8 +42,11 @@
# define NULL 0 /* from <stddef.h> */
#endif
#ifndef __div_t
# define __div_t 1
typedef struct div_t { int quot, rem; } div_t;
/* type of the value returned by the div function. */
#endif
typedef struct ldiv_t { long int quot, rem; } ldiv_t;
/* type of the value returned by the ldiv function. */
......
......@@ -139,6 +139,15 @@ $Label RFS r1
EXPORT |_ldfp|
EXPORT |_stfp|
EXPORT |__fpclassifyf|
EXPORT |__fpclassifyd|
EXPORT |__signbitf|
EXPORT |__signbitd|
EXPORT copysign
EXPORT copysignf
EXPORT nextafter
EXPORT nextafterf
EXPORT |__rt_stkovf_split_small|
EXPORT |__rt_stkovf_split_big|
EXPORT |__rt_divtest|
......@@ -149,6 +158,11 @@ $Label RFS r1
EXPORT |__rt_wr2chk|
EXPORT |__rt_wr4chk|
EXPORT fmin
EXPORT fminf
EXPORT fmax
EXPORT fmaxf
EXPORT sin
EXPORT cos
EXPORT exp
......@@ -309,6 +323,15 @@ Raised
B |_postmortem| ; and if user insists on returning from
; signal handler, complain loudly!
div
ldiv
imaxdiv
FunctionEntry "a1"
MOV a1, a3
BL _kernel_sdiv ; a1 := a2 / a1, a2 := a2 % a1
Pull "ip,lr"
STMIA ip, {a1,a2}
Return ,LinkNotStacked
|x$multiply|
......@@ -816,6 +839,312 @@ chunks_deallocated
]
Return ,LinkNotStacked
FP_ZERO * 0
FP_SUBNORMAL * 1
FP_NORMAL * 2
FP_INFINITY * 3
FP_NAN * 4
; These functions always take arguments in registers, to prevent
; signalling NaN problems. The wrapper macros ensure they are
; passed the correct type, so the initial store can't cause an
; exception.
|__fpclassifyf|
STFS f0, [sp, #-4]!
LDR r0, [sp], #4
BICS r0, r0, #&80000000 ; ignore sign; EQ if Exp and M == 0 (and r0 == 0 == FP_ZERO)
ASSERT FP_ZERO = 0
Return ,LinkNotStacked,EQ
MOVS r2, r0, LSR #23 ; R2 := Exp; EQ if Exp == 0
MOVEQ r0, #FP_SUBNORMAL
Return ,LinkNotStacked,EQ
TEQ r2, #&ff
MOVNE r0, #FP_NORMAL
Return ,LinkNotStacked,NE
MOVS r2, r0, LSL #9 ; R2 := M; EQ if M == 0
MOVEQ r0, #FP_INFINITY
MOVNE r0, #FP_NAN
Return ,LinkNotStacked
|__fpclassifyd|
STFD f0, [sp, #-8]!
LDMIA sp!, {r0, r1}
BICS r0, r0, #&80000000 ; ignore sign; EQ if Exp and MHi == 0
TEQEQS r1, #0 ; EQ if Exp and M == 0 (and r0 == 0 == FP_ZERO)
ASSERT FP_ZERO = 0
Return ,LinkNotStacked,EQ
MOVS r2, r0, LSR #20 ; R2 := Exp; EQ if Exp == 0
MOVEQ r0, #FP_SUBNORMAL
Return ,LinkNotStacked,EQ
ADDS r0, r0, #&00100000 ; If Exp = &7FF then R0 := &800xxxxx, so MI
MOVPL r0, #FP_NORMAL
Return ,LinkNotStacked,PL
ORRS r0, r1, r0, LSL #1 ; Look for any non-zero bits (except top bit of R0)
MOVEQ r0, #FP_INFINITY
MOVNE r0, #FP_NAN
Return ,LinkNotStacked
|__signbitf|
STFS f0, [sp, #-4]!
LDR r0, [sp], #4
MOV r0, r0, LSR #31
Return ,LinkNotStacked
|__signbitd|
STFD f0, [sp, #-8]!
LDR r0, [sp], #8
MOV r0, r0, LSR #31
Return ,LinkNotStacked
copysign
STFD f1, [sp, #-8]!
LDR r2, [sp], #8
TEQ r2, #0 ; MI if y negative
ABSD f0, f0
MNFMID f0, f0
Return ,LinkNotStacked
copysignf
STFS f1, [sp, #-4]!
LDR r1, [sp], #4
TEQ r1, #0 ; MI if y negative
ABSS f0, f0
MNFMIS f0, f0
Return ,LinkNotStacked
; Back to normal calling conventions
nextafter
[ :LNOT:FloatingPointArgsInRegs
STMFD sp!, {r0-r3}
LDFD f0, [sp], #8
LDFD f1, [sp], #8
]
CMF f1, f0
BEQ copysign
BGT nextup
BMI nextdown
; unordered
ADFD f0, f0, f1 ; do the NaN propagation + exceptions
Return ,LinkNotStacked
nextup
[ FloatingPointArgsInRegs
STFD f0, [sp, #-8]!
LDMFD sp!, {r0, r1}
]
TEQ r0, #0
BPL nextbigger
BMI nextsmaller_neg
nextdown
[ FloatingPointArgsInRegs
STFD f0, [sp, #-8]!
LDMFD sp!, {r0, r1}
]
TEQ r0, #0
BPL nextsmaller_pos
BMI nextbigger
nextbigger
CMN r0, #&00100000
Return ,LinkNotStacked,CS ; catch infinity (NaN already done)
Return ,LinkNotStacked,VS
nextbigger_finite
; For all finite cases (both +ve and -ve), it's just a 64-bit +1:
;
; 00000000 00000000 -> 00000000 00000001 0 => smallest subnormal
; 000FFFFF FFFFFFFF -> 00100000 00000000 largest subnormal => smallest normal
; 7FEFFFFF FFFFFFFF -> 7FF00000 00000000 largest normal => infinity
ADDS r1, r1, #1
ADC r0, r0, #0
retval STMFD sp!, {r0, r1}
LDFD f0, [sp], #8
Return ,LinkNotStacked
nextsmaller_pos
; 7FF00000 00000000 -> 7FEFFFFF FFFFFFFF +infinity => largest +ve normal
; 00100000 00000000 -> 000FFFFF FFFFFFFF smallest +ve normal => largest +ve subnormal
; 00000000 00000001 -> 00000000 00000000 smallest +ve subnormal => +0
; 00000000 00000000 -> FFFFFFFF FFFFFFFF clears carry, so we can catch +0 => -ve case
SUBS r1, r1, #1
SBCS r0, r0, #0
STMCSFD sp!, {r0, r1}
LDFCSD f0, [sp], #8
LDFCCD f0, tiny_neg ; -0 => smallest +ve subnormal
Return ,LinkNotStacked
nextsmaller_neg
; FFF00000 00000000 -> FFEFFFFF FFFFFFFF -infinity => largest -ve normal
; 80100000 00000000 -> 800FFFFF FFFFFFFF smallest -ve normal => largest -ve subnormal
; 80000000 00000001 -> 80000000 00000000 smallest -ve subnormal => -0
; 80000000 00000000 -> 7FFFFFFF FFFFFFFF sets overflow, so we can catch -0 => +ve case
SUBS r1, r1, #1
SBCS r0, r0, #0
STMVCFD sp!, {r0, r1}
LDFVCD f0, [sp], #8
LDFVSD f0, tiny_pos ; -0 => smallest +ve subnormal
Return ,LinkNotStacked
nexttowardf
[ :LNOT:FloatingPointArgsInRegs
STMFD sp!, {r0-r3}
LDFD f0, [sp], #8
LDFD f1, [sp], #8
]
MVFS f0, f0
CMF f1, f0
BEQ copysignf
BGT nextupf
BMI nextdownf
; unordered
ADFS f0, f0, f1 ; do the NaN propagation + exceptions
Return ,LinkNotStacked
nextafterf
[ :LNOT:FloatingPointArgsInRegs
STMFD sp!, {r0-r3}
LDFD f0, [sp], #8
LDFD f1, [sp], #8
]
MVFS f0, f0
MVFS f1, f1
CMF f1, f0
BEQ copysignf
BGT nextupf
BMI nextdownf
; unordered
ADFS f0, f0, f1 ; do the NaN propagation + exceptions
Return ,LinkNotStacked
nextupf
STFS f0, [sp, #-4]!
LDR r0, [sp], #4
TEQ r0, #0
BPL nextbiggerf
BMI nextsmallerf_neg
nextdownf
STFS f0, [sp, #-4]!
LDR r0, [sp], #4
TEQ r0, #0
BPL nextsmallerf_pos
BMI nextbiggerf
nextbiggerf
ADD r1, r0, #&00800000 ; spot infinities - NaNs already
TEQ r0, r1 ; caught in nexttowardf. Return
; them unchanged (MI if +/-inf)
; For all finite cases (both +ve and -ve), it's just a 32-bit +1:
;
; 00000000 -> 00000001 0 => smallest subnormal
; 007FFFFF -> 00800000 largest subnormal => smallest normal
; 7F7FFFFF -> 7F800000 largest normal => infinity
ADDPL r0, r0, #1
STRPL r0, [sp, #-4]!
LDFPLS f0, [sp], #4
Return ,LinkNotStacked
nextsmallerf_pos
; 7F800000 -> 7F7FFFFF +infinity => largest +ve normal
; 00800000 -> 007FFFFF smallest +ve normal => largest +ve subnormal
; 00000001 -> 00000000 smallest +ve subnormal => +0
; 00000000 -> FFFFFFFF clears carry, so we can catch +0 => -ve case
SUBS r0, r0, #1
STRCS r0, [sp, #-4]!
LDFCSS f0, [sp], #4
LDFCCS f0, tiny_negf ; -0 => smallest +ve subnormal
Return ,LinkNotStacked
nextsmallerf_neg
; FF800000 -> FF7FFFFF -infinity => largest -ve normal
; 80800000 -> 807FFFFF smallest -ve normal => largest -ve subnormal
; 80000001 -> 80000000 smallest -ve subnormal => -0
; 80000000 -> 7FFFFFFF sets overflow, so we can catch -0 => +ve case
SUBS r0, r0, #1
STRVC r0, [sp, #-4]!
LDFVCS f0, [sp], #4
LDFVSS f0, tiny_posf ; -0 => smallest +ve subnormal
Return ,LinkNotStacked
tiny_neg
DCD &80000000
DCD &00000001
tiny_pos
DCD &00000000
tiny_posf
DCD &00000001
tiny_negf
DCD &80000001
fmax
[ :LNOT:FloatingPointArgsInRegs
STMFD sp!, {r0-r3}
LDFD f0, [sp], #8
LDFD f1, [sp], #8
]
CMF f1, f0
MVFGTD f0, f1
Return ,LinkNotStacked,VC
fcmpnan CMF f0, #0
MVFVSD f0, f1
Return ,LinkNotStacked
fmaxf
[ :LNOT:FloatingPointArgsInRegs
STMFD sp!, {r0-r3}
LDFD f0, [sp], #8
LDFD f1, [sp], #8
]
MVFS f0, f0
MVFS f1, f1
CMF f1, f0
MVFGTS f0, f1
Return ,LinkNotStacked,VC
B fcmpnan
fmin
[ :LNOT:FloatingPointArgsInRegs
STMFD sp!, {r0-r3}
LDFD f0, [sp], #8
LDFD f1, [sp], #8
]
CMF f1, f0
MVFMID f0, f1
Return ,LinkNotStacked,VC
B fcmpnan
fminf
[ :LNOT:FloatingPointArgsInRegs
STMFD sp!, {r0-r3}
LDFD f0, [sp], #8
LDFD f1, [sp], #8
]
MVFS f0, f0
MVFS f1, f1
CMF f1, f0
MVFMIS f0, f1
Return ,LinkNotStacked,VC
B fcmpnan
[ {FALSE}
fmaf
[ :LNOT:FloatingPointArgsInRegs
STMFD sp!, {r0-r3}
LDFD f0, [sp], #8
LDFD f1, [sp], #8
]
LDFD f2, [sp, #0]
MVFS f0, f0
MVFS f1, f1
MVFS f2, f2
MUFE f0, f0, f1 ; totally accurate result
ADFS f0, f0, f2
Return ,LinkNotStacked
]
sin
[ :LNOT: FloatingPointArgsInRegs
STMFD sp!, {r0, r1}
......@@ -824,6 +1153,17 @@ sin
SIND f0, f0
Return ,LinkNotStacked
[ {FALSE}
sinf
[ :LNOT: FloatingPointArgsInRegs
STMFD sp!, {r0, r1}
LDFD f0, [sp], #8
]
MVFS f0, f0
SINS f0, f0
Return ,LinkNotStacked
]
cos
[ :LNOT: FloatingPointArgsInRegs
STMFD sp!, {r0, r1}
......@@ -832,6 +1172,17 @@ cos
COSD f0, f0
Return ,LinkNotStacked
[ {FALSE}
cosf
[ :LNOT: FloatingPointArgsInRegs
STMFD sp!, {r0, r1}
LDFD f0, [sp], #8
]
MVFS f0, f0
COSS f0, f0
Return ,LinkNotStacked
]
exp
[ :LNOT: FloatingPointArgsInRegs
STMFD sp!, {r0, r1}
......@@ -871,14 +1222,28 @@ huge_val
DCD &7FEFFFFF ; put constant where it is easy to find
DCD &FFFFFFFF
huge_errorf
MOV r0, #ERANGE
LDFS f0, huge_valf
B Set_errno
huge_valf
DCD &7F800000
negative_error
MOV r0, #EDOM
LDFD f0, negative_huge_val ; @@@@!!!!
B Set_errno
negative_errorf
MOV r0, #EDOM
LDFS f0, negative_huge_valf ; @@@@!!!!
B Set_errno
negative_huge_valf
DCD &FF800000 ; put constant where it is easy to find
underflow_error
MOV r0, #ERANGE
MVFD f0, #0
; MVFD f0, #0
B Set_errno
log10
......@@ -913,6 +1278,19 @@ sqrt
SQTD f0, f0
Return ,LinkNotStacked
[ {FALSE}
sqrtf
[ :LNOT: FloatingPointArgsInRegs
STMFD sp!, {r0, r1}
LDFD f0, [sp], #8
]
MVFS f0, f0
CMFE f0, #0
BMI negative_errorf
SQTS f0, f0
Return ,LinkNotStacked
]
tan
[ :LNOT: FloatingPointArgsInRegs
STMFD sp!, {r0, r1}
......@@ -927,6 +1305,23 @@ tan
Return ,LinkNotStacked, EQ
B huge_error
[ {FALSE}
tanf
[ :LNOT: FloatingPointArgsInRegs
STMFD sp!, {r0, r1}
DisableFPInterrupts
LDFD f0, [sp], #8
|
DisableFPInterrupts
]
MVFS f0, f0
TANS f0, f0
ReEnableFPInterrupts
TST r1, #&07
Return ,LinkNotStacked, EQ
B huge_errorf
]
atan
[ :LNOT: FloatingPointArgsInRegs
STMFD sp!, {r0, r1}
......
......@@ -103,9 +103,9 @@
Entry bsearch, imported, , __bsearch, , IMPORT
Entry qsort, imported, , , 4
Entry abs, imported, , , 1
Entry div, imported, , , 2
Entry div, , , , 2
Entry labs, imported, , , 1
Entry ldiv, imported, , , 2
Entry ldiv, , , , 2
Entry remove, imported, , , 1
Entry rename, imported, , , 2
Entry tmpfile, imported, , , 1
......@@ -214,5 +214,44 @@
Entry _swi, imported, , unveneered
Entry _swix, imported, , unveneered
Entry __fpclassifyf, , , unveneered
Entry __fpclassifyd, , , unveneered
Entry __signbitf, , , unveneered
Entry __signbitd, , , unveneered
Entry copysign, , , unveneered
Entry copysignf, , , unveneered
Entry nan, imported, , unveneered
Entry nanf, imported, , unveneered
Entry nextafter, , , unveneered
Entry nextafterf, , , unveneered
Entry fdim, imported, , unveneered
Entry fdimf, imported, , unveneered
Entry fmax, , , unveneered
Entry fmaxf, , , unveneered
Entry fmin, , , unveneered
Entry fminf, , , unveneered
Entry fabsf, imported, , unveneered
Entry hypot, imported, , unveneered
Entry hypotf, imported, , unveneered
Entry feclearexcept, imported, , unveneered
Entry fegetexceptflag, imported, , unveneered
Entry feraiseexcept, imported, , unveneered
Entry fesetexceptflag, imported, , unveneered
Entry fetestexcept, imported, , unveneered
Entry fegetround, imported, , unveneered
Entry fesetround, imported, , unveneered
Entry fegetenv, imported, , unveneered
Entry feholdexcept, imported, , unveneered
Entry fesetenv, imported, , unveneered
Entry feupdateenv, imported, , unveneered
Entry _snprintf, imported, , unveneered
Entry snprintf, imported, , unveneered
Entry vsnprintf, imported, , unveneered
Entry vfscanf, imported, , unveneered
Entry vscanf, imported, , unveneered
Entry vsscanf, imported, , unveneered
; __va_illegal_arg 0
END
......@@ -242,34 +242,58 @@ extern int _sys_close_(FILEHANDLE fh);
#ifdef IBMFLOAT
/* This version works with IBM 360 floating point. */
#define SignBit 0x80000000
#define ExpBits 0x7F000000
#define MHiBits 0x00FFFFFF
#ifdef BYTESEX_EVEN
typedef union {struct {int mhi:24, x:7, s:1; unsigned mlo; } i;
struct {unsigned sxmhi, mlo; } w;
double d; } fp_number;
#else
typedef union {struct {int s:1, x:7, mhi:24; unsigned mlo; } i;
struct {unsigned sxmhi, mlo; } w;
double d; } fp_number;
#endif
#else
#define SignBit 0x80000000
#define ExpBits 0x7FF00000
#define MHiBits 0x000FFFFF
#define ExpBits_S 0x7F800000
#define MBits_S 0x007FFFFF
#ifdef BYTESEX_EVEN
typedef union {struct {int m:23, x:8, s:1; } i;
unsigned w;
float s; } fp_number_single;
#else
typedef union {struct {int s:1, x:8, m:23; } i;
unsigned w;
float s; } fp_number_single;
#endif
#ifndef OTHER_WORD_ORDER_FOR_FP_NUMBERS
/* This version works with the ARM floating point emulator - it may have */
/* to be reworked when or if floating point hardware is installed */
# ifdef BYTESEX_EVEN
typedef union {struct {int mhi:20, x:11, s:1; unsigned mlo; } i;
struct {unsigned sxmhi, mlo; } w;
double d; } fp_number;
# else
typedef union {struct {int s:1, x:11, mhi:20; unsigned mlo; } i;
struct {unsigned sxmhi, mlo; } w;
double d; } fp_number;
# endif
#else /* OTHER_WORD_ORDER_FOR_FP_NUMBERS */
# ifdef BYTESEX_EVEN
typedef union {struct {unsigned mlo; int mhi:20, x:11, s:1; } i;
struct {unsigned mlo, sxmhi; } w;
double d; } fp_number;
# else
typedef union {struct {unsigned mlo; int s:1, x:11, mhi:20; } i;
struct {unsigned mlo, sxmhi; } w;
double d; } fp_number;
# endif
#endif /* OTHER_WORD_ORDER_FOR_FP_NUMBERS */
......
; Copyright 2002 Pace Micro Technology plc
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
FE_INVALID * &01
FE_DIVBYZERO * &02
FE_OVERFLOW * &04
FE_UNDERFLOW * &08
FE_INEXACT * &10
FE_ALL_EXCEPT * &1F
FE_TONEAREST * 0
FE_DFL_ENV * 0
GET objmacs.s
CodeArea
; int feclearexcept(int excepts)
Function feclearexcept, leaf
RFS ip
AND a2, a1, #FE_ALL_EXCEPT
BIC ip, ip, a2
WFS ip
BIC a1, a1, #FE_ALL_EXCEPT
Return ,,LinkNotStacked
; int fegetexceptflag(fexcept_t *flagp, int excepts)
Function fegetexceptflag, leaf
RFS ip
AND a3, a2, #FE_ALL_EXCEPT
AND ip, ip, a3
STR ip, [a1]
BIC a1, a2, #FE_ALL_EXCEPT
Return ,,LinkNotStacked
; int fesetexceptflag(const fexcept_t *flagp, int excepts)
Function fesetexceptflag, leaf
RFS ip
LDR a1, [a1]
AND a3, a2, #FE_ALL_EXCEPT
AND a1, a1, a3
BIC ip, ip, a3
ORR ip, ip, a1
WFS ip
BIC a1, a2, #FE_ALL_EXCEPT
Return ,,LinkNotStacked
; int fetestexcept(int excepts);
Function fetestexcept, leaf
RFS ip
AND a1, a1, #FE_ALL_EXCEPT
AND a1, ip, a1
Return ,,LinkNotStacked
; int fegetround(void)
Function fegetround, leaf
MOV a1, #FE_TONEAREST
Return ,,LinkNotStacked
; int fesetround(int round)
Function fesetround, leaf
EOR a1, a1, #FE_TONEAREST
Return ,,LinkNotStacked
;int fegetenv(fenv_t *envp)
Function fegetenv, leaf
RFS ip
STR ip, [a1]
Return ,,LinkNotStacked
; int feholdexcept(fenv_t *envp)
Function feholdexcept, leaf
RFS ip
STR ip, [a1]
BIC ip, ip, #FE_ALL_EXCEPT
BIC ip, ip, #FE_ALL_EXCEPT :SHL: 16
WFS ip
MOV a1, #0
Return ,,LinkNotStacked
; int fesetenv(const fenv_t *envp)
Function fesetenv, leaf
TEQ a1, #FE_DFL_ENV
LDRNE ip, [a1]
MOVEQ ip, #&00070000
WFS ip
RFS a1
EOR a1, a1, ip
BIC a1, a1, #&FF000000
Return ,,LinkNotStacked
; int feupdateenv(const fenv_t *envp)
Function feupdateenv, leaf
TEQ a1, #FE_DFL_ENV
LDRNE ip, [a1]
MOVEQ ip, #&00070000
RFS a4 ; read current status
WFS ip ; write new status
RFS a3 ; check we wrote it successfully
EOR a3, a3, ip
BICS a1, a3, #&FF000000
Return ,,LinkNotStacked, NE ; return nonzero if not
AND a1, a4, #FE_ALL_EXCEPT ; a1 := previous exceptions
; fall through
; int feraiseexcept(int excepts)
Function feraiseexcept, leaf
; Yuck. No easy way to do this. We need five sums that
; will generate each exception in turn.
TST a1, #FE_INVALID
MVFNES f0, #0
DVFNES f0, f0, #0
TST a1, #FE_DIVBYZERO
MVFNES f0, #1
DVFNES f0, f0, #0
TST a1, #FE_OVERFLOW
LDFNES f0, Huge
MUFNES f0, f0, #2
TST a1, #FE_UNDERFLOW
LDFNES f0, Tiny
MUFNES f0, f0, #0.5
TST a1, #FE_INEXACT
LDFNES f0, TwoToTwentyEight
ADFNES f0, f0, #1
BIC a1, a1, #FE_ALL_EXCEPT
Return ,,LinkNotStacked
TwoToTwentyEight
DCD &4D800000 ; 1.0 x 2^28
Tiny
DCD &00000001 ; smallest denormalised single
Huge
DCD &7F7FFFFF ; largest normalised single
END
......@@ -301,7 +301,15 @@ FoundLibraryChunk
; I suppose it would be friendly to check here that there are
; no fewer entries in the library than in the stub.
; So let's do it:
LDR r12, StubInitValue
LDR r1, [r14, #LI_EntryBase-LI_ItemSize]
LDR r4, [r14, #LI_EntryEnd-LI_ItemSize]
SUB r4, r4, r1 ; r4 = size of our table
ADD r4, r2, r4 ; r4 = end of client table we know
01 CMP r4, r3
STRLO r12, [r3, #-4]! ; fill in excess with MOV PC,#0
BLO %BT01
; Branch patchup for SWI Lib_Init1 to 4
; r2 = entry vector base
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment