Improved support for freestanding.

This commit is contained in:
Christoffer Lerno
2023-01-25 11:14:03 +01:00
committed by Christoffer Lerno
parent a22ebbb0ef
commit 39801a304d
15 changed files with 240 additions and 65 deletions

View File

@@ -120,13 +120,11 @@ macro sign(x)
return ($typeof(x))(x < 0 ? -1 : 1);
}
$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, double) @extname("atan2");
extern fn float _atan2f(float, float) @extname("atan2f");
/**
* @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
* @checked x + y
**/
macro atan2(x, y)
{
$if ($typeof(x).typeid == float.typeid && $typeof(y).typeid == float.typeid):
@@ -136,6 +134,10 @@ macro atan2(x, y)
$endif;
}
/**
* @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
* @checked x + y
**/
macro atan(x)
{
$if ($typeof(x).typeid == float.typeid):
@@ -145,32 +147,6 @@ macro atan(x)
$endif;
}
$else:
macro atan2(x, y)
{
$if ($typeof(x).typeid == float.typeid && $typeof(y).typeid == float.typeid):
return atan::_atan2f(x, y);
$else:
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`
**/
@@ -625,3 +601,9 @@ macro is_nan(x)
$assert(false, "Type cannot be used with is_nan");
$endswitch;
}
extern fn double _atan(double x) @extname("atan");
extern fn float _atanf(float x) @extname("atanf");
extern fn double _atan2(double, double) @extname("atan2");
extern fn float _atan2f(float, float) @extname("atan2f");

View File

@@ -0,0 +1,45 @@
module std::math::nolibc;
$if (!env::COMPILER_LIBC_AVAILABLE):
fn double _ceil(double x) @weak @extname("ceil")
{
ulong ui = bitcast(x, ulong);
int e = (int)((ui >> 52) & 0x7ff);
if (e >= 0x3ff + 52 || x == 0) return x;
// y = int(x) - x, where int(x) is an integer neighbor of x
double y = ui >> 63 ? (x - TOINT) + TOINT - x : (x + TOINT) - TOINT - x;
// special case because of non-nearest rounding modes
if (e <= 0x3ff - 1)
{
@force_eval_add(y, 0);
return ui >> 63 ? -0.0 : 1;
}
return y < 0 ? x + y + 1 : x + y;
}
fn float _ceilf(float x) @weak @extname("ceilf")
{
uint u = bitcast(x, uint);
int e = (int)((u >> 23) & 0xff) - 0x7f;
switch
{
case e >= 23:
return x;
case e >= 0:
uint m = 0x007fffff >> e;
if (u & m == 0) return x;
@force_eval_add(x, 0x1p120f);
if (u >> 31 == 0) u += m;
u &= ~m;
case u >> 31 != 0:
@force_eval_add(x, 0x1p120f);
return -0.0f;
case u << 1 != 0:
return 1;
}
return bitcast(u, float);
}
$endif;

View File

@@ -0,0 +1,15 @@
module std::math::nolibc;
$if (!env::COMPILER_LIBC_AVAILABLE):
fn float exp2f_broken(float x) @extname("exp2f") @weak
{
unreachable("'exp2f' not supported");
}
fn float exp2_broken(float x) @extname("exp2") @weak
{
unreachable("'exp2' not supported");
}
$endif;

View File

@@ -1,21 +1,45 @@
module std::math::nolibc;
$if (!env::COMPILER_LIBC_AVAILABLE):
fn double floor(double x) @weak @extname("floor")
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)
if (e >= 0x3ff + 52 || x == 0) return x;
// y = int(x) - x, where int(x) is an integer neighbor of x
double 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);
@force_eval_add(y, 0);
return ui >> 63 ? -1 : 0;
}
return y > 0 ? x + y - 1 : x + y;
}
}
fn float _floorf(float x) @weak @extname("floorf")
{
uint u = bitcast(x, uint);
int e = (int)((u >> 23) & 0xff) - 0x7f;
switch
{
case e >= 23:
return x;
case e >= 0:
uint m = 0x007fffff >> e;
if (u & m == 0) return x;
@force_eval_add(x, 0x1p120f);
if (u >> 31) u += m;
u &= ~m;
case u >> 31 == 0:
@force_eval_add(x, 0x1p120f);
u = 0;
case (u << 1 != 0):
return -1;
}
return bitcast(u, float);
}
$endif;

View File

@@ -0,0 +1,9 @@
module std::math::nolibc;
const double TOINT = 1 / math::DOUBLE_EPSILON;
const float TOINTF = (float)(1 / math::FLOAT_EPSILON);
macro @force_eval_add(&x, v)
{
@volatile_store(x, @volatile_load(x) + v);
}

View File

@@ -0,0 +1,15 @@
module std::math::nolibc;
$if (!env::COMPILER_LIBC_AVAILABLE):
fn float powf_broken(float x) @extname("powf") @weak
{
unreachable("'powf' not supported");
}
fn float pow_broken(float x) @extname("pow") @weak
{
unreachable("'pow' not supported");
}
$endif;

View File

@@ -170,8 +170,8 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec)
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 */
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
@@ -221,7 +221,7 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec)
if (ih == 2)
{
z = 1.0 - z;
if (carry != 0) z -= nolibc::scalbn(1.0, q0);
if (carry != 0) z -= nolibc::_scalbn(1.0, q0);
}
}
@@ -265,7 +265,7 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec)
else
{
/* break z into 24-bit if necessary */
z = nolibc::scalbn(z,-q0);
z = nolibc::_scalbn(z,-q0);
if (z >= 0x1p24)
{
fw = (double)(int)(0x1p-24 * z);
@@ -281,7 +281,7 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec)
}
/* convert integer "bit" chunk to floating-point value */
fw = nolibc::scalbn(1.0 , q0);
fw = nolibc::_scalbn(1.0 , q0);
for (int i = jz; i >= 0; i --)
{
q[i] = fw * (double)iq[i];

View File

@@ -0,0 +1,56 @@
module std::math::nolibc;
$if (!env::COMPILER_LIBC_AVAILABLE):
fn double _round(double x) @extname("round") @weak
{
ulong u = bitcast(x, ulong);
int e = (int)((u >> 52) & 0x7ff);
if (e >= 0x3ff + 52) return x;
if (u >> 63) x = -x;
if (e < 0x3ff - 1)
{
/* raise inexact if x!=0 */
@force_eval_add(x, TOINT);
return 0 * x;
}
double y = (x + TOINT) - TOINT - x;
switch
{
case y > 0.5:
y = y + x - 1;
case y <= -0.5:
y = y + x + 1;
default:
y = y + x;
}
if (u >> 63) y = -y;
return y;
}
fn float roundf(float x) @extname("roundf") @weak
{
uint u = bitcast(x, uint);
int e = (u >> 23) & 0xff;
if (e >= 0x7f + 23) return x;
if (u >> 31) x = -x;
if (e < 0x7f - 1)
{
@force_eval_add(x, TOINTF);
return 0 * x;
}
float y = (x + TOINTF) - TOINTF - x;
switch
{
case y > 0.5f:
y = y + x - 1;
case y <= -0.5f:
y = y + x + 1;
default:
y = y + x;
}
if (u >> 31) y = -y;
return y;
}
$endif;

View File

@@ -1,6 +1,8 @@
module std::math::nolibc;
fn double scalbn(double x, int n) @weak @extname("scalbn")
$if (!env::COMPILER_LIBC_AVAILABLE):
fn double _scalbn(double x, int n) @weak @extname("scalbn")
{
switch
{
@@ -24,4 +26,6 @@ fn double scalbn(double x, int n) @weak @extname("scalbn")
}
}
return x * bitcast(((ulong)(0x3ff + n)) << 52, double);
}
}
$endif;

View File

@@ -149,6 +149,10 @@ fn float cosf_broken(float x) @extname("cosf") @weak
{
unreachable("'cosf' not supported");
}
fn float sincosf_broken(float x) @extname("sincosf") @weak
{
unreachable("'sincosf' not supported");
}
fn double sin_broken(double x) @extname("sin") @weak
{
@@ -158,20 +162,10 @@ fn double cos_broken(double x) @extname("cos") @weak
{
unreachable("'cos' not supported");
}
fn float roundf_broken(float x) @extname("roundf") @weak
fn double sincos_broken(double x) @extname("sincos") @weak
{
unreachable("'roundf' not supported");
unreachable("'sinccos' 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,31 @@
module std::math::nolibc;
$if (!env::COMPILER_LIBC_AVAILABLE):
fn double _trunc(double x) @weak @extname("trunc")
{
ulong i = bitcast(x, ulong);
int e = (int)((i >> 52) & 0x7ff) - 0x3ff + 12;
if (e >= 52 + 12) return x;
if (e < 12) e = 1;
ulong m = ((ulong)-1) >> e;
if (i & m == 0) return x;
@force_eval_add(x, 0x1p120f);
i &= ~m;
return bitcast(i, double);
}
fn float _truncf(float x) @weak @extname("truncf")
{
uint i = bitcast(x, uint);
int e = (int)((i >> 23) & 0xff) - 0x7f + 9;
if (e >= 23 + 9) return x;
if (e < 9) e = 1;
uint m = ((uint)-1) >> e;
if (i & m == 0) return x;
@force_eval_add(x, 0x1p120f);
i &= ~m;
return bitcast(i, float);
}
$endif;