Improved support for freestanding.

This commit is contained in:
Christoffer Lerno
2023-01-24 22:11:48 +01:00
committed by Christoffer Lerno
parent f37f779e5a
commit a22ebbb0ef
15 changed files with 1152 additions and 45 deletions

View File

@@ -1,7 +1,14 @@
module std::io::os;
import libc;
$if (env::OS_TYPE == OsType.WIN32):
$if (!env::COMPILER_LIBC_AVAILABLE):
fn String! getcwd(Allocator* allocator = mem::default_allocator())
{
unreachable("'getcwd' not available");
}
$elif (env::OS_TYPE == OsType.WIN32):
extern fn Char16* _wgetcwd(Char16* buffer, int maxlen);
extern fn usz wcslen(Char16* str);

View File

@@ -4,9 +4,6 @@
module libc;
// stdlib
// Constants need to be per os/arch
const int EXIT_FAILURE = 1;
const int EXIT_SUCCESS = 0;
@@ -24,8 +21,6 @@ struct LongDivResult
long rem;
}
fn Errno errno()
{
return (Errno)os::errno();
@@ -38,6 +33,10 @@ fn void errno_set(Errno e)
define TerminateFunction = fn void();
define CompareFunction = fn int(void*, void*);
define JmpBuf = CInt[$$JMP_BUF_SIZE];
$if (env::COMPILER_LIBC_AVAILABLE):
extern fn double atof(char* str);
extern fn int atoi(char* str);
extern fn CLongLong atoll(char* str);
@@ -58,8 +57,6 @@ extern fn LongDivResult ldiv(long number, long denom);
extern fn int rand();
extern fn void srand(uint seed);
define JmpBuf = CInt[$$JMP_BUF_SIZE];
extern fn void longjmp(JmpBuf* buffer, CInt value);
$if (env::OS_TYPE == OsType.WIN32):
// TODO win32 aarch64
@@ -75,7 +72,7 @@ extern fn void* memchr(void* str, int c, usz n);
extern fn int memcmp(void* str1, void* str2, usz n);
extern fn void* memcpy(void* dest, void* src, usz n);
extern fn void* memmove(void* dest, void* src, usz n);
extern fn void* memset(void* dest, usz n);
extern fn void* memset(void* dest, CInt value, usz n);
extern fn char* strcat(char* dest, char* src);
extern fn char* strncat(char* dest, char* src, usz n);
extern fn char* strchr(char* str, int c);
@@ -99,13 +96,61 @@ extern fn void* calloc(usz count, usz size);
extern fn void* free(void*);
extern fn void* realloc(void* ptr, usz size);
$else:
fn void longjmp(JmpBuf* buffer, CInt value) @weak @extname("longjmp")
{
unreachable("longjmp unavailable");
}
fn CInt setjmp(JmpBuf* buffer) @weak @extname("setjmp")
{
unreachable("setjmp unavailable");
}
fn void* malloc(usz size) @weak @extname("malloc")
{
unreachable("malloc unavailable");
}
fn void* calloc(usz count, usz size) @weak @extname("calloc")
{
unreachable("calloc unavailable");
}
fn void* free(void*) @weak @extname("free")
{
unreachable("free unavailable");
}
fn void* realloc(void* ptr, usz size) @weak @extname("realloc")
{
unreachable("realloc unavailable");
}
fn void* memcpy(void* dest, void* src, usz n) @weak @extname("memcpy")
{
for (usz i = 0; i < n; i++) ((char*)dest)[i] = ((char*)src)[i];
return dest;
}
fn void* memmove(void* dest, void* src, usz n) @weak @extname("memmove")
{
return memcpy(dest, src, n) @inline;
}
fn void* memset(void* dest, CInt value, usz n) @weak @extname("memset")
{
for (usz i = 0; i < n; i++) ((char*)dest)[i] = (char)value;
return dest;
}
$endif;
// stdio
define Fpos = long;
define CFile = void*;
$switch (env::OS_TYPE):
$case OsType.LINUX:
$if (env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.LINUX):
extern CFile __stdin @extname("stdin");
extern CFile __stdout @extname("stdout");
extern CFile __stderr @extname("stderr");
@@ -115,7 +160,7 @@ $case OsType.LINUX:
macro CFile stdin() { return __stdin; }
macro CFile stdout() { return __stdout; }
macro CFile stderr() { return __stderr; }
$case OsType.MACOSX:
$elif (env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.MACOSX):
extern CFile __stdinp;
extern CFile __stdoutp;
extern CFile __stderrp;
@@ -124,19 +169,18 @@ $case OsType.MACOSX:
macro CFile stdin() { return __stdinp; }
macro CFile stdout() { return __stdoutp; }
macro CFile stderr() { return __stderrp; }
$case OsType.WIN32:
$elif (env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.WIN32):
extern fn CFile __acrt_iob_func(CInt c);
extern fn usz _msize(void* ptr);
macro usz malloc_size(void* ptr) { return _msize(ptr); }
macro CFile stdin() { return __acrt_iob_func(0); }
macro CFile stdout() { return __acrt_iob_func(1); }
macro CFile stderr() { return __acrt_iob_func(2); }
$default:
$else:
macro CFile stdin() { return (CFile*)(uptr)0; }
macro CFile stdout() { return (CFile*)(uptr)1; }
macro CFile stderr() { return (CFile*)(uptr)2; }
$endswitch;
$endif;
const HAS_MALLOC_SIZE =
env::OS_TYPE == OsType.LINUX
@@ -159,6 +203,8 @@ const int FILENAME_MAX = 1024;
define Errno = distinct CInt;
define SeekIndex = CLong;
$if (env::COMPILER_LIBC_AVAILABLE):
extern fn int fclose(CFile stream);
extern fn void clearerr(CFile stream);
extern fn int feof(CFile stream);
@@ -190,13 +236,78 @@ extern fn char* fgets(char* str, int n, CFile stream);
extern fn int fputc(int c, CFile stream);
extern fn int getc(CFile stream);
extern fn int getchar();
extern fn int putc(char c, CFile stream);
extern fn int putc(int c, CFile stream);
extern fn int putchar(int c);
extern fn int puts(char* str);
extern fn int ungetc(int c, CFile stream);
extern fn void perror(char* str);
extern fn isz getline(char** linep, usz* linecapp, CFile stream);
$else:
fn int fseek(CFile stream, SeekIndex offset, int whence) @weak @extname("fseek")
{
unreachable("'fseek' not available.");
}
fn CFile fopen(char* filename, char* mode) @weak @extname("fopen")
{
unreachable("'fopen' not available.");
}
fn usz fwrite(void* ptr, usz size, usz nmemb, CFile stream) @weak @extname("fwrite")
{
unreachable("'fwrite' not available.");
}
fn usz fread(void* ptr, usz size, usz nmemb, CFile stream) @weak @extname("fread")
{
unreachable("'fread' not available.");
}
fn CFile fclose(CFile) @weak @extname("fclose")
{
unreachable("'fclose' not available.");
}
fn int fflush(CFile stream) @weak @extname("fflush")
{
unreachable("'fflush' not available.");
}
fn int fputc(int c, CFile stream) @weak @extname("fputc")
{
unreachable("'fputc' not available.");
}
fn char* fgets(char* str, int n, CFile stream) @weak @extname("fgets")
{
unreachable("'fgets' not available.");
}
fn int fgetc(CFile stream) @weak @extname("fgetc")
{
unreachable("'fgetc' not available.");
}
fn int feof(CFile stream) @weak @extname("feof")
{
unreachable("'feof' not available.");
}
fn int putc(int c, CFile stream) @weak @extname("putc")
{
unreachable("'putc' not available.");
}
fn int putchar(int c) @weak @extname("putchar")
{
unreachable("'putchar' not available.");
}
fn int puts(char* str) @weak @extname("puts")
{
unreachable("'puts' not available.");
}
$endif;
// vsprintf vprintf not supported
// time.h

View File

@@ -1,21 +1,18 @@
module libc::os;
$switch (env::OS_TYPE):
$case LINUX:
$if (env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.LINUX):
extern fn int* __errno_location();
macro int errno() => *__errno_location();
macro void errno_set(int err) => *(__errno_location()) = err;
$case MACOSX:
$elif (env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.MACOSX):
extern fn int* __error();
macro int errno() => *__error();
macro void errno_set(int err) => *(__error()) = err;
$case WIN32:
$elif (env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.WIN32):
macro int errno()
{
@@ -29,9 +26,10 @@ macro void errno_set(int err) => _set_errno(err);
extern fn void _get_errno(int* result);
extern fn void _set_errno(int err);
$default:
$else:
macro int errno() => 1;
fn void errno_set(int err) {}
tlocal int _errno_c3 = 0;
fn void errno_set(int err) => _errno_c3 = err;
fn int errno() => _errno_c3;
$endswitch;
$endif;

View File

@@ -124,8 +124,17 @@ $if (env::COMPILER_LIBC_AVAILABLE):
extern fn double _atan(double x) @extname("atan");
extern fn float _atanf(float x) @extname("atanf");
extern fn double _atan2(double x) @extname("atan2");
extern fn float _atan2f(float x) @extname("atan2f");
extern fn double _atan2(double, double) @extname("atan2");
extern fn float _atan2f(float, float) @extname("atan2f");
macro atan2(x, y)
{
$if ($typeof(x).typeid == float.typeid && $typeof(y).typeid == float.typeid):
return _atan2f(x, y);
$else:
return _atan2(x, y);
$endif;
}
macro atan(x)
{
@@ -136,16 +145,32 @@ macro atan(x)
$endif;
}
$else:
macro atan2(x, y)
{
$if ($typeof(x).typeid == float.typeid && $typeof(y).typeid == float.typeid):
return _atan2f(x);
return atan::_atan2f(x, y);
$else:
return _atan2(x);
return atan::_atan2(x, y);
$endif;
}
macro atan(x)
{
$if ($typeof(x).typeid == float.typeid):
return atan::_atanf(x);
$else:
return atan::_atan(x);
$endif;
}
$endif;
/**
* @require values::@is_floatlike(x) `The input must be a floating point value or float vector`
**/
@@ -575,15 +600,28 @@ macro next_power_of_2(x)
return y;
}
import std::io;
private macro equals_vec(v1, v2)
{
var $elements = v1.len;
var abs_diff = math::abs(v1 - v2);
io::printfn("diff %s", abs_diff);
var abs_v1 = math::abs(v1);
var abs_v2 = math::abs(v2);
io::printfn("abs %s", abs_v1);
$typeof(abs_v2) eps = 1;
return abs_diff.comp_le(FLOAT_EPSILON * math::max(abs_v1, abs_v2, eps)).and();
}
}
macro uint double.high_word(double d) => (uint)(bitcast(d, ulong) >> 32);
macro uint double.low_word(double d) => (uint)bitcast(d, ulong);
macro uint float.word(float d) => bitcast(d, uint);
macro is_nan(x)
{
$switch ($typeof(x)):
$case float:
return bitcast(x, uint) & 0x7fffffff > 0x7f800000;
$case double:
return bitcast(x, ulong) & (((ulong)-1) >> 1) > (0x7ffu64 << 52);
$default:
$assert(false, "Type cannot be used with is_nan");
$endswitch;
}

47
lib/std/math/math_libc.c3 Normal file
View File

@@ -0,0 +1,47 @@
/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* atan(x)
* Method
* 1. Reduce x to positive by atan(x) = -atan(-x).
* 2. According to the integer k=4t+0.25 chopped, t=x, the argument
* is further reduced to one of the following intervals and the
* arctangent of t is evaluated by the corresponding formula:
*
* [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
* [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
* [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
* [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
* [39/16,INF] atan(x) = atan(INF) + atan( -1/t )
*
* Constants:
* The hexadecimal values are the intended ones for the following
* constants. The decimal values may be used, provided that the
* compiler will convert from decimal to binary accurately enough
* to produce the hexadecimal values shown.
*/
/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
module std::math;

View File

@@ -0,0 +1,324 @@
module std::math::nolibc::atan;
$if (!env::COMPILER_LIBC_AVAILABLE):
private const double[*] ATANHI = {
4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
};
private const double[*] ATANLO = {
2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
};
private const double[*] AT = {
3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
-1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
-1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
-7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
-5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
-3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
};
fn double _atan(double x) @weak @extname("atan")
{
int id = void;
uint ix = x.high_word();
uint sign = ix >> 31;
ix &= 0x7fffffff;
switch
{
case ix >= 0x44100000:
/* if |x| >= 2^66 */
if (math::is_nan(x)) return x;
double z = ATANHI[3] + 0x1p-120f;
return sign ? -z : z;
case ix < 0x3fdc0000:
/* |x| < 0.4375 */
if (ix < 0x3e400000)
{
/* |x| < 2^-27 */
if (ix < 0x00100000)
{
/* raise underflow for subnormal x */
(float)@volatile_load(x);
}
return x;
}
id = -1;
case ix < 0x3ff30000:
/* |x| < 1.1875 */
x = math::abs(x);
if (ix < 0x3fe60000)
{
/* 7/16 <= |x| < 11/16 */
id = 0;
x = (2 * x - 1) / (2 + x);
}
else
{ /* 11/16 <= |x| < 19/16 */
id = 1;
x = (x - 1) / (x + 1);
}
case ix < 0x40038000:
x = math::abs(x);
/* |x| < 2.4375 */
id = 2;
x = (x - 1.5) / (1 + 1.5 * x);
default:
/* 2.4375 <= |x| < 2^66 */
id = 3;
x = -1 / math::abs(x);
}
/* end of argument reduction */
double z = x * x;
double w = z * z;
/* break sum from i=0 to 10 AT[i]z**(i+1) into odd and even poly */
double s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10])))));
double s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9]))));
if (id < 0) return x - x * (s1 + s2);
z = ATANHI[id] - (x * (s1 + s2) - ATANLO[id] - x);
return sign ? -z : z;
}
private const float[*] ATANHIF = {
4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
};
private const float[*] ATANLOF = {
5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
};
private const float[*] ATF = {
3.3333328366e-01,
-1.9999158382e-01,
1.4253635705e-01,
-1.0648017377e-01,
6.1687607318e-02,
};
fn float _atanf(float x) @weak @extname("atanf")
{
int id = void;
uint ix = x.word();
uint sign = ix >> 31;
ix &= 0x7fffffff;
if (ix >= 0x4c800000)
{
/* if |x| >= 2**26 */
if (math::is_nan(x)) return x;
float z = ATANHIF[3] + 0x1p-120f;
return sign ? -z : z;
}
switch
{
case ix < 0x3ee00000:
/* |x| < 0.4375 */
if (ix < 0x39800000)
{
/* |x| < 2**-12 */
if (ix < 0x00800000)
{
/* raise underflow for subnormal x */
float f = @volatile_load(x);
f = f * f;
}
return x;
}
id = -1;
case ix < 0x3f980000:
/* |x| < 1.1875 */
x = math::abs(x);
if (ix < 0x3f300000)
{
/* 7/16 <= |x| < 11/16 */
id = 0;
x = (2.0f * x - 1.0f) / (2.0f + x);
break;
}
/* 11/16 <= |x| < 19/16 */
id = 1;
x = (x - 1.0f) / (x + 1.0f);
case ix < 0x401c0000:
x = math::abs(x);
/* |x| < 2.4375 */
id = 2;
x = (x - 1.5f) / (1.0f + 1.5f * x);
default:
/* 2.4375 <= |x| < 2**26 */
x = math::abs(x);
id = 3;
x = -1.0f / x;
}
/* end of argument reduction */
float z = x * x;
float w = z * z;
/* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
float s1 = z * (ATF[0] + w * (ATF[2] + w * ATF[4]));
float s2 = w * (ATF[1] + w * ATF[3]);
if (id < 0) return x - x * (s1 + s2) * 10000;
z = ATANHIF[id] - ((x * (s1 + s2) - ATANLOF[id]) - x);
return sign ? -z : z;
}
private const PI_LO = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
private macro void extract_words(double d, uint* hi, uint* lo)
{
ulong rep = bitcast(d, ulong);
*hi = (uint)(rep >> 32);
*lo = (uint)rep;
}
fn double _atan2(double y, double x) @weak @extname("atan2")
{
if (math::is_nan(x) || math::is_nan(y)) return x + y;
uint lx = void;
uint ix = void;
extract_words(x, &ix, &lx);
uint ly = void;
uint iy = void;
extract_words(y, &iy, &ly);
// x = 1.0
if ((ix - 0x3ff00000) | lx == 0) return _atan(y);
// 2*sign(x) + sign(y)
uint m = ((iy >> 31) & 1) | ((ix >> 30) & 2);
ix = ix & 0x7fffffff;
iy = iy & 0x7fffffff;
// when y = 0
if (iy | ly == 0)
{
switch (m)
{
case 0:
case 1: return y; /* atan(+-0,+anything)=+-0 */
case 2: return math::PI; /* atan(+0,-anything) = pi */
case 3: return -math::PI; /* atan(-0,-anything) =-pi */
}
}
// when x = 0 */
if (ix | lx == 0) return m & 1 ? -math::PI_2 : math::PI_2;
/* when x is INF */
if (ix == 0x7ff00000)
{
if (iy == 0x7ff00000)
{
switch (m)
{
case 0: return math::PI_4; /* atan(+INF,+INF) */
case 1: return -math::PI_4; /* atan(-INF,+INF) */
case 2: return math::PI_4 + math::PI_2; /* atan(+INF,-INF) */
case 3: return - (math::PI_4 + math::PI_2); /* atan(-INF,-INF) */
}
unreachable();
}
switch (m)
{
case 0: return 0.0; /* atan(+...,+INF) */
case 1: return -0.0; /* atan(-...,+INF) */
case 2: return math::PI; /* atan(+...,-INF) */
case 3: return -math::PI; /* atan(-...,-INF) */
}
unreachable();
}
/* |y/x| > 0x1p64 */
if (ix + (64 << 20) < iy || iy == 0x7ff00000) return m & 1 ? -math::PI_2 : math::PI_2;
/* z = atan(|y/x|) without spurious underflow */
double z = ((m & 2) && iy + (64 << 20) < ix) ? 0 : _atan(math::abs(y/x));
switch (m)
{
case 0: return z; /* atan(+,+) */
case 1: return -z; /* atan(-,+) */
case 2: return math::PI - (z - PI_LO); /* atan(+,-) */
default: return (z - PI_LO) - math::PI; /* atan(-,-) */
}
}
private const float PI_F = 3.1415927410e+00; /* 0x40490fdb */
private const float PI_LO_F = -8.7422776573e-08; /* 0xb3bbbd2e */
fn float _atan2f(float y, float x) @weak @extname("atan2f")
{
if (math::is_nan(x) || math::is_nan(y)) return x + y;
uint ix = bitcast(x, uint);
uint iy = bitcast(y, uint);
/* x=1.0 */
if (ix == 0x3f800000) return _atanf(y);
/* 2*sign(x)+sign(y) */
uint m = ((iy >> 31) & 1) | ((ix >> 30) & 2);
ix &= 0x7fffffff;
iy &= 0x7fffffff;
/* when y = 0 */
if (iy == 0)
{
switch (m)
{
case 0:
case 1: return y; /* atan(+-0,+anything)=+-0 */
case 2: return PI_F; /* atan(+0,-anything) = pi */
case 3: return -PI_F; /* atan(-0,-anything) =-pi */
}
unreachable();
}
/* when x = 0 */
if (ix == 0) return m & 1 ? -(float)math::PI_2 : (float)math::PI_2;
/* when x is INF */
if (ix == 0x7f800000)
{
if (iy == 0x7f800000)
{
switch (m)
{
case 0: return (float)math::PI_4; /* atan(+INF,+INF) */
case 1: return (float)-math::PI_4; /* atan(-INF,+INF) */
case 2: return (float)(math::PI_4 + math::PI_2); /*atan(+INF,-INF)*/
case 3: return -(float)(math::PI_4 + math::PI_2); /*atan(-INF,-INF)*/
}
unreachable();
}
switch (m)
{
case 0: return 0.0f; /* atan(+...,+INF) */
case 1: return -0.0f; /* atan(-...,+INF) */
case 2: return PI_F; /* atan(+...,-INF) */
case 3: return -PI_F; /* atan(-...,-INF) */
}
unreachable();
}
/* |y/x| > 0x1p26 */
if (ix + 26 << 23 < iy || iy == 0x7f800000) return m & 1 ? -(float)math::PI_2 : (float)math::PI_2;
/* z = atan(|y/x|) with correct underflow */
/*|y/x| < 0x1p-26, x < 0 */
float z = (m & 2 && iy + 26 << 23 < ix) ? 0.0f : _atanf(math::abs(y / x));
switch (m)
{
case 0: return z; /* atan(+,+) */
case 1: return -z; /* atan(-,+) */
case 2: return PI_F - (z - PI_LO_F); /* atan(+,-) */
default: return (z - PI_LO_F) - PI_F; /* atan(-,-) */
}
}
$endif;

View File

@@ -0,0 +1,21 @@
module std::math::nolibc;
fn double floor(double x) @weak @extname("floor")
{
const double TOINT = 1 / math::DOUBLE_EPSILON;
ulong ui = bitcast(x, ulong);
int e = (int)((ui >> 52) & 0x7ff);
double y;
if (e >= 0x3ff+52 || x == 0) return x;
/* y = int(x) - x, where int(x) is an integer neighbor of x */
y = ui >> 63 ? (x - TOINT) + TOINT - x : (x + TOINT) - TOINT - x;
/* special case because of non-nearest rounding modes */
if (e <= 0x3ff-1)
{
@volatile_load(y);
return ui >> 63 ? -1 : 0;
}
return y > 0 ? x + y - 1 : x + y;
}

View File

@@ -0,0 +1,347 @@
module std::math::nolibc::rempi;
import std::math;
/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
* Debugged and optimized by Bruce D. Evans.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* __rem_pio2f(x,y)
*
* return the remainder of x rem pi/2 in *y
* use double precision for everything except passing x
* use __rem_pio2_large() for large x
*/
$if (!env::COMPILER_LIBC_AVAILABLE):
/*
* invpio2: 53 bits of 2/pi
* pio2_1: first 25 bits of pi/2
* pio2_1t: pi/2 - pio2_1
*/
private const double TOINT = 1.5 / math::DOUBLE_EPSILON;
private const double PIO4 = 0x1.921fb6p-1;
private const double INVPIO2 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */
private const double PIO2_1 = 1.57079631090164184570e+00; /* 0x3FF921FB, 0x50000000 */
private const double PIO2_1T = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */
fn int __rem_pio2f(float x, double *y)
{
uint ux = bitcast(x, uint);
uint ix = ux & 0x7fffffff;
/* 25+53 bit pi is good enough for medium size */
if (ix < 0x4dc90fdb)
{
// |x| ~< 2^28*(pi/2), medium size
// Use a specialized rint() to get f.
uint f = (uint)(((double)x * INVPIO2 + TOINT) - TOINT);
int n = (int)f;
*y = x - f * PIO2_1 - f * PIO2_1T;
/* Matters with directed rounding. */
if (*y < -PIO4) // likely false
{
n--;
f--;
*y = x - f * PIO2_1 - f * PIO2_1T;
}
else if (*y > PIO4) // likely false
{
n++;
f++;
*y = x - f * PIO2_1 - f * PIO2_1T;
}
return n;
}
if (ix >= 0x7f800000)
{
// x is inf or NaN */
*y = x-x;
return 0;
}
/* scale x into [2^23, 2^24-1] */
int sign = ux >> 31;
int e0 = (ix >> 23) - (0x7f + 23); /* e0 = ilogb(|x|)-23, positive */
ux = ix - e0 << 23;
double tx = bitcast(ux, float);
double ty = void;
int n = __rem_pio2_large(&tx,&ty, e0, 1, 0);
if (sign)
{
*y = (float)-ty;
return -n;
}
*y = (float)ty;
return n;
}
/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
const int[*] INIT_JK = {3,4,4,6}; /* initial value for jk */
const int[*] IPIO2 = {
0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, };
const double[*] PIO2 = {
1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
};
fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec)
{
double[20] f = void;
double[20] fq = void;
double[20] q = void;
int[20] iq = void;
double fw = void;
/* initialize jk*/
int jk = INIT_JK[prec];
int jp = jk;
/* determine jx,jv,q0, note that 3>q0 */
int jx = nx - 1;
int jv = (e0 - 3) / 24;
if (jv < 0) jv = 0;
int q0 = e0 - 24 * (jv + 1);
// set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk]
int j = jv - jx;
int m = jx + jk;
for (int i = 0; i <= m; i++, j++)
{
f[i] = j < 0 ? 0.0 : (double)IPIO2[j];
}
// compute q[0],q[1],...q[jk]
for (int i = 0; i <= jk; i++)
{
for (j = 0, fw = 0.0; j <= jx; j++) fw += x[j] * f[jx + i - j];
q[i] = fw;
}
int jz = jk;
double z = void;
int ih = 0;
int n = void;
while (1)
{
/* distill q[] into iq[] reversingly */
z = q[jz];
j = jz;
for (int i = 0; j > 0; i++, j--)
{
fw = (double)(int)(0x1p-24 * z);
iq[i] = (int)(z - 0x1p24 * fw);
z = q[j - 1] + fw;
}
// compute n
z = nolibc::scalbn(z, q0); /* actual value of z */
z -= 8.0 * nolibc::floor(z * 0.125); /* trim off integer >= 8 */
n = (int)z;
z -= (double)n;
switch
{
case q0 > 0:
// need iq[jz-1] to determine n
int i = iq[jz - 1] >> (24 - q0);
n += i;
iq[jz - 1] -= i << (24 - q0);
ih = iq[jz - 1] >> (23 - q0);
case q0 == 0:
ih = iq[jz - 1] >> 23;
case z >= 0.5:
ih = 2;
}
if (ih > 0)
{
/* q > 0.5 */
n += 1;
int carry = 0;
for (int i = 0; i < jz; i++)
{
/* compute 1-q */
j = iq[i];
if (carry == 0)
{
if (j != 0)
{
carry = 1;
iq[i] = 0x1000000 - j;
}
}
else
{
iq[i] = 0xffffff - j;
}
}
if (q0 > 0)
{
/* rare case: chance is 1 in 12 */
switch (q0)
{
case 1: iq[jz - 1] &= 0x7fffff;
case 2: iq[jz - 1] &= 0x3fffff;
}
}
if (ih == 2)
{
z = 1.0 - z;
if (carry != 0) z -= nolibc::scalbn(1.0, q0);
}
}
// check if recomputation is needed
if (z == 0.0)
{
j = 0;
for (int i = jz - 1; i >= jk; i--) j |= iq[i];
if (j == 0)
{
/* need recomputation */
int k = 1;
for (; iq[jk - k] == 0; k++); /* k = no. of terms needed */
for (int i = jz + 1; i <= jz + k; i++)
{
/* add q[jz+1] to q[jz+k] */
f[jx + i] = (double)IPIO2[jv + i];
for (j = 0, fw = 0.0; j <= jx; j++)
fw += x[j] * f[jx + i - j];
q[i] = fw;
}
jz += k;
continue;
}
}
break;
}
/* chop off zero terms */
if (z == 0.0)
{
jz -= 1;
q0 -= 24;
while (iq[jz] == 0)
{
jz--;
q0 -= 24;
}
}
else
{
/* break z into 24-bit if necessary */
z = nolibc::scalbn(z,-q0);
if (z >= 0x1p24)
{
fw = (double)(int)(0x1p-24 * z);
iq[jz] = (int)(z - 0x1p24 * fw);
jz += 1;
q0 += 24;
iq[jz] = (int)fw;
}
else
{
iq[jz] = (int)z;
}
}
/* convert integer "bit" chunk to floating-point value */
fw = nolibc::scalbn(1.0 , q0);
for (int i = jz; i >= 0; i --)
{
q[i] = fw * (double)iq[i];
fw *= 0x1p-24;
}
/* compute PIO2[0,...,jp]*q[jz,...,0] */
for (int i = jz; i >= 0; i--)
{
for (fw = 0.0, int k = 0; k <= jp && k <= jz-i; k++) fw += PIO2[k] * q[i + k];
fq[jz - i] = fw;
}
/* compress fq[] into y[] */
switch (prec)
{
case 0:
fw = 0.0;
for (int i = jz; i >= 0; i--) fw += fq[i];
y[0] = ih == 0 ? fw : -fw;
case 1:
case 2:
fw = 0.0;
for (int i = jz; i >= 0; i--)
fw += fq[i];
// TODO: drop excess precision here once double_t is used
fw = (double)fw;
y[0] = ih == 0 ? fw : -fw;
fw = fq[0]-fw;
for (int i = 1; i <= jz; i++) fw += fq[i];
y[1] = ih == 0 ? fw : -fw;
case 3: /* painful */
for (int i = jz; i > 0; i--)
{
fw = fq[i - 1] + fq[i];
fq[i] += fq[i - 1] - fw;
fq[i - 1] = fw;
}
for (int i = jz; i > 1; i--)
{
fw = fq[i-1] + fq[i];
fq[i] += fq[i - 1] - fw;
fq[i - 1] = fw;
}
for (fw = 0.0, int i = jz; i >= 2; i--)
fw += fq[i];
if (ih == 0)
{
y[0] = fq[0];
y[1] = fq[1];
y[2] = fw;
}
else
{
y[0] = -fq[0];
y[1] = -fq[1];
y[2] = -fw;
}
}
return n & 7;
}
$endif;

View File

@@ -0,0 +1,27 @@
module std::math::nolibc;
fn double scalbn(double x, int n) @weak @extname("scalbn")
{
switch
{
case n > 1023:
x *= 0x1p1023;
n -= 1023;
if (n > 1023)
{
x *= 0x1p1023;
n -= 1023;
if (n > 1023) n = 1023;
}
case n < -1022:
x *= 0x1p-1022 * 0x1p53;
n += 1022 - 53;
if (n < -1022)
{
x *= 0x1p-1022 * 0x1p53;
n += 1022 - 53;
if (n < -1022) n = -1022;
}
}
return x * bitcast(((ulong)(0x3ff + n)) << 52, double);
}

View File

@@ -0,0 +1,177 @@
module std::math::nolibc::trig;
$if (!env::COMPILER_LIBC_AVAILABLE):
/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
* Optimized by Bruce D. Evans.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
private const double S1PI2_F = math::PI_2; /* 0x3FF921FB, 0x54442D18 */
private const double S2PI2_F = math::PI; /* 0x400921FB, 0x54442D18 */
private const double S3PI2_F = math::PI + math::PI_2; /* 0x4012D97C, 0x7F3321D2 */
private const double S4PI2_F = math::PI + math::PI; /* 0x401921FB, 0x54442D18 */
fn float _sinf(float x) @weak @extname("sinf")
{
uint ix = bitcast(x, uint);
int sign = ix >> 31;
ix &= 0x7fffffff;
switch
{
case ix <= 0x3f490fda:
// |x| ~<= pi/4
if (ix < 0x39800000)
{
/* |x| < 2**-12 */
// raise inexact if x!=0 and underflow if subnormal
if (ix < 0x00800000)
{
@volatile_load(x) / 0x1p120f;
}
else
{
@volatile_load(x) + 0x1p120f;
}
return x;
}
return __sindf(x);
case ix <= 0x407b53d1:
// |x| ~<= 5*pi/4
if (ix <= 0x4016cbe3)
{
// |x| ~<= 3pi/4
if (sign) return -__cosdf(x + S1PI2_F);
return __cosdf(x - S1PI2_F);
}
return __sindf(sign ? -(x + S2PI2_F) : -(x - S2PI2_F));
case ix <= 0x40e231d5:
// |x| ~<= 9*pi/4
if (ix <= 0x40afeddf)
{
// |x| ~<= 7*pi/4
return sign ? __cosdf(x + S3PI2_F) : -__cosdf(x - S3PI2_F);
}
return __sindf(sign ? x + S4PI2_F : x - S4PI2_F);
case ix >= 0x7f800000:
// sin(Inf or NaN) is NaN
return x - x;
}
/* general argument reduction needed */
double y = void;
int n = rempi::__rem_pio2f(x, &y);
switch (n & 3)
{
case 0: return __sindf(y);
case 1: return __cosdf(y);
case 2: return __sindf(-y);
default: return -__cosdf(y);
}
unreachable();
}
/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
* Optimized by Bruce D. Evans.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */
private const double S1 = -0x15555554cbac77.0p-55; /* -0.166666666416265235595 */
private const double S2 = 0x111110896efbb2.0p-59; /* 0.0083333293858894631756 */
private const double S3 = -0x1a00f9e2cae774.0p-65; /* -0.000198393348360966317347 */
private const double S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */
fn float __sindf(double x)
{
double z = x * x;
double w = z * z;
double r = S3 + z * S4;
double s = z * x;
return (float)((x + s * (S1 + z * S2)) + s * w * r);
}
/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
* Debugged and optimized by Bruce D. Evans.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */
private const double C0 = -0x1ffffffd0c5e81.0p-54; /* -0.499999997251031003120 */
private const double C1 = 0x155553e1053a42.0p-57; /* 0.0416666233237390631894 */
private const double C2 = -0x16c087e80f1e27.0p-62; /* -0.00138867637746099294692 */
private const double C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */
fn float __cosdf(double x)
{
/* Try to optimize for parallel evaluation as in __tandf.c. */
double z = x * x;
double w = z * z;
double r = C2 + z * C3;
return (float)(((1.0f + z * C0) + w * C1) + (w * z) * r);
}
fn float cosf_broken(float x) @extname("cosf") @weak
{
unreachable("'cosf' not supported");
}
fn double sin_broken(double x) @extname("sin") @weak
{
unreachable("'sin' not supported");
}
fn double cos_broken(double x) @extname("cos") @weak
{
unreachable("'cos' not supported");
}
fn float roundf_broken(float x) @extname("roundf") @weak
{
unreachable("'roundf' not supported");
}
fn double round_broken(double x) @extname("round") @weak
{
unreachable("'round' not supported");
}
fn float powf_broken(float x) @extname("powf") @weak
{
unreachable("'powf' not supported");
}
$endif;

View File

@@ -0,0 +1,6 @@
module std::thread;
define NativeMutex = distinct int;
define NativeConditionVariable = distinct int;
define NativeOnceFlag = distinct int;
define NativeThread = distinct int;

View File

@@ -3,9 +3,15 @@ module std::thread;
enum ThreadModel
{
WIN32,
POSIX
POSIX,
NONE
}
$if (env::COMPILER_LIBC_AVAILABLE):
const ThreadModel THREAD_MODEL = env::OS_TYPE == OsType.WIN32 ? ThreadModel.WIN32 : ThreadModel.POSIX;
$else:
const ThreadModel THREAD_MODEL = NONE;
$endif;
define MutexType = distinct int;