mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add --strip-unused.
This commit is contained in:
committed by
Christoffer Lerno
parent
0aa776d61b
commit
a0a5c940f1
@@ -276,7 +276,7 @@ add_executable(c3c
|
||||
src/compiler/expr.c
|
||||
src/utils/time.c
|
||||
src/utils/http.c
|
||||
)
|
||||
src/compiler/sema_liveness.c)
|
||||
|
||||
|
||||
if (C3_USE_TB)
|
||||
|
||||
@@ -98,21 +98,21 @@ extern fn void* realloc(void* ptr, usz size);
|
||||
|
||||
$else:
|
||||
|
||||
fn void longjmp(JmpBuf* buffer, CInt value) @weak @extern("longjmp")
|
||||
fn void longjmp(JmpBuf* buffer, CInt value) @weak @extern("longjmp") @nostrip
|
||||
{
|
||||
unreachable("longjmp unavailable");
|
||||
}
|
||||
|
||||
fn CInt setjmp(JmpBuf* buffer) @weak @extern("setjmp")
|
||||
fn CInt setjmp(JmpBuf* buffer) @weak @extern("setjmp") @nostrip
|
||||
{
|
||||
unreachable("setjmp unavailable");
|
||||
}
|
||||
|
||||
fn void* malloc(usz size) @weak @extern("malloc")
|
||||
fn void* malloc(usz size) @weak @extern("malloc") @nostrip
|
||||
{
|
||||
unreachable("malloc unavailable");
|
||||
}
|
||||
fn void* calloc(usz count, usz size) @weak @extern("calloc")
|
||||
fn void* calloc(usz count, usz size) @weak @extern("calloc") @nostrip
|
||||
{
|
||||
unreachable("calloc unavailable");
|
||||
}
|
||||
@@ -121,23 +121,23 @@ fn void* free(void*) @weak @extern("free")
|
||||
unreachable("free unavailable");
|
||||
}
|
||||
|
||||
fn void* realloc(void* ptr, usz size) @weak @extern("realloc")
|
||||
fn void* realloc(void* ptr, usz size) @weak @extern("realloc") @nostrip
|
||||
{
|
||||
unreachable("realloc unavailable");
|
||||
}
|
||||
|
||||
fn void* memcpy(void* dest, void* src, usz n) @weak @extern("memcpy")
|
||||
fn void* memcpy(void* dest, void* src, usz n) @weak @extern("memcpy") @nostrip
|
||||
{
|
||||
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 @extern("memmove")
|
||||
fn void* memmove(void* dest, void* src, usz n) @weak @extern("memmove") @nostrip
|
||||
{
|
||||
return memcpy(dest, src, n) @inline;
|
||||
}
|
||||
|
||||
fn void* memset(void* dest, CInt value, usz n) @weak @extern("memset")
|
||||
fn void* memset(void* dest, CInt value, usz n) @weak @extern("memset") @nostrip
|
||||
{
|
||||
for (usz i = 0; i < n; i++) ((char*)dest)[i] = (char)value;
|
||||
return dest;
|
||||
@@ -246,69 +246,69 @@ extern fn isz getline(char** linep, usz* linecapp, CFile stream);
|
||||
|
||||
$else:
|
||||
|
||||
fn int fseek(CFile stream, SeekIndex offset, int whence) @weak @extern("fseek")
|
||||
fn int fseek(CFile stream, SeekIndex offset, int whence) @weak @extern("fseek") @nostrip
|
||||
{
|
||||
unreachable("'fseek' not available.");
|
||||
}
|
||||
fn CFile fopen(ZString filename, ZString mode) @weak @extern("fopen")
|
||||
fn CFile fopen(ZString filename, ZString mode) @weak @extern("fopen") @nostrip
|
||||
{
|
||||
unreachable("'fopen' not available.");
|
||||
}
|
||||
|
||||
fn CFile freopen(ZString filename, ZString mode, CFile stream) @weak @extern("fopen")
|
||||
fn CFile freopen(ZString filename, ZString mode, CFile stream) @weak @extern("fopen") @nostrip
|
||||
{
|
||||
unreachable("'freopen' not available.");
|
||||
}
|
||||
|
||||
fn usz fwrite(void* ptr, usz size, usz nmemb, CFile stream) @weak @extern("fwrite")
|
||||
fn usz fwrite(void* ptr, usz size, usz nmemb, CFile stream) @weak @extern("fwrite") @nostrip
|
||||
{
|
||||
unreachable("'fwrite' not available.");
|
||||
}
|
||||
|
||||
fn usz fread(void* ptr, usz size, usz nmemb, CFile stream) @weak @extern("fread")
|
||||
fn usz fread(void* ptr, usz size, usz nmemb, CFile stream) @weak @extern("fread") @nostrip
|
||||
{
|
||||
unreachable("'fread' not available.");
|
||||
}
|
||||
|
||||
fn CFile fclose(CFile) @weak @extern("fclose")
|
||||
fn CFile fclose(CFile) @weak @extern("fclose") @nostrip
|
||||
{
|
||||
unreachable("'fclose' not available.");
|
||||
}
|
||||
|
||||
fn int fflush(CFile stream) @weak @extern("fflush")
|
||||
fn int fflush(CFile stream) @weak @extern("fflush") @nostrip
|
||||
{
|
||||
unreachable("'fflush' not available.");
|
||||
}
|
||||
|
||||
fn int fputc(int c, CFile stream) @weak @extern("fputc")
|
||||
fn int fputc(int c, CFile stream) @weak @extern("fputc") @nostrip
|
||||
{
|
||||
unreachable("'fputc' not available.");
|
||||
}
|
||||
|
||||
fn char* fgets(ZString str, int n, CFile stream) @weak @extern("fgets")
|
||||
fn char* fgets(ZString str, int n, CFile stream) @weak @extern("fgets") @nostrip
|
||||
{
|
||||
unreachable("'fgets' not available.");
|
||||
}
|
||||
|
||||
fn int fgetc(CFile stream) @weak @extern("fgetc")
|
||||
fn int fgetc(CFile stream) @weak @extern("fgetc") @nostrip
|
||||
{
|
||||
unreachable("'fgetc' not available.");
|
||||
}
|
||||
|
||||
fn int feof(CFile stream) @weak @extern("feof")
|
||||
fn int feof(CFile stream) @weak @extern("feof") @nostrip
|
||||
{
|
||||
unreachable("'feof' not available.");
|
||||
}
|
||||
|
||||
fn int putc(int c, CFile stream) @weak @extern("putc")
|
||||
fn int putc(int c, CFile stream) @weak @extern("putc") @nostrip
|
||||
{
|
||||
unreachable("'putc' not available.");
|
||||
}
|
||||
fn int putchar(int c) @weak @extern("putchar")
|
||||
fn int putchar(int c) @weak @extern("putchar") @nostrip
|
||||
{
|
||||
unreachable("'putchar' not available.");
|
||||
}
|
||||
fn int puts(ZString str) @weak @extern("puts")
|
||||
fn int puts(ZString str) @weak @extern("puts") @nostrip
|
||||
{
|
||||
unreachable("'puts' not available.");
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
module std::math;
|
||||
|
||||
fn float __roundevenf(float f) @extern("roundevenf") @weak
|
||||
fn float __roundevenf(float f) @extern("roundevenf") @weak @nostrip
|
||||
{
|
||||
// Slow implementation
|
||||
return round(f / 2) * 2;
|
||||
}
|
||||
|
||||
fn double __roundeven(double d) @extern("roundeven") @weak
|
||||
fn double __roundeven(double d) @extern("roundeven") @weak @nostrip
|
||||
{
|
||||
// Slow implementation
|
||||
return round(d / 2) * 2;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math;
|
||||
|
||||
fn int128 __divti3(int128 a, int128 b) @extern("__divti3") @weak
|
||||
fn int128 __divti3(int128 a, int128 b) @extern("__divti3") @weak @nostrip
|
||||
{
|
||||
int128 sign_a = a >> 127; // -1 : 0
|
||||
int128 sign_b = b >> 127; // -1 : 0
|
||||
@@ -10,7 +10,7 @@ fn int128 __divti3(int128 a, int128 b) @extern("__divti3") @weak
|
||||
return __udivti3(unsigned_a, unsigned_b) @inline ^ sign_a + (-sign_a);
|
||||
}
|
||||
|
||||
fn uint128 __umodti3(uint128 n, uint128 d) @extern("__umodti3") @weak
|
||||
fn uint128 __umodti3(uint128 n, uint128 d) @extern("__umodti3") @weak @nostrip
|
||||
{
|
||||
// Ignore d = 0
|
||||
uint128 sr = (d ? $$clz(d) : 128) - (n ? $$clz(n) : 128);
|
||||
@@ -34,7 +34,7 @@ fn uint128 __umodti3(uint128 n, uint128 d) @extern("__umodti3") @weak
|
||||
return r;
|
||||
}
|
||||
|
||||
fn uint128 __udivti3(uint128 n, uint128 d) @extern("__udivti3") @weak
|
||||
fn uint128 __udivti3(uint128 n, uint128 d) @extern("__udivti3") @weak @nostrip
|
||||
{
|
||||
// Ignore d = 0
|
||||
uint128 sr = (d ? $$clz(d) : 128) - (n ? $$clz(n) : 128);
|
||||
@@ -60,7 +60,7 @@ fn uint128 __udivti3(uint128 n, uint128 d) @extern("__udivti3") @weak
|
||||
return n;
|
||||
}
|
||||
|
||||
fn int128 __modti3(int128 a, int128 b) @extern("__modti3") @weak
|
||||
fn int128 __modti3(int128 a, int128 b) @extern("__modti3") @weak @nostrip
|
||||
{
|
||||
int128 sign = b >> 127;
|
||||
uint128 unsigned_b = (uint128)(b ^ sign) + (-sign);
|
||||
@@ -83,7 +83,7 @@ union Int128bits @private
|
||||
uint128 all;
|
||||
}
|
||||
|
||||
fn uint128 __lshrti3(uint128 a, uint b) @extern("__lshrti3") @weak
|
||||
fn uint128 __lshrti3(uint128 a, uint b) @extern("__lshrti3") @weak @nostrip
|
||||
{
|
||||
Int128bits result;
|
||||
result.all = a;
|
||||
@@ -101,7 +101,7 @@ fn uint128 __lshrti3(uint128 a, uint b) @extern("__lshrti3") @weak
|
||||
return result.all;
|
||||
}
|
||||
|
||||
fn int128 __ashrti3(int128 a, uint b) @extern("__ashrti3") @weak
|
||||
fn int128 __ashrti3(int128 a, uint b) @extern("__ashrti3") @weak @nostrip
|
||||
{
|
||||
Int128bits result;
|
||||
result.all = a;
|
||||
@@ -119,7 +119,7 @@ fn int128 __ashrti3(int128 a, uint b) @extern("__ashrti3") @weak
|
||||
return result.all;
|
||||
}
|
||||
|
||||
fn int128 __ashlti3(int128 a, uint b) @extern("__ashlti3") @weak
|
||||
fn int128 __ashlti3(int128 a, uint b) @extern("__ashlti3") @weak @nostrip
|
||||
{
|
||||
Int128bits result;
|
||||
result.all = a;
|
||||
@@ -158,7 +158,7 @@ fn int128 __mulddi3(ulong a, ulong b) @private
|
||||
return r.all;
|
||||
}
|
||||
|
||||
fn int128 __multi3(int128 a, int128 b) @extern("__multi3") @weak
|
||||
fn int128 __multi3(int128 a, int128 b) @extern("__multi3") @weak @nostrip
|
||||
{
|
||||
Int128bits x = { .all = a };
|
||||
Int128bits y = { .all = b };
|
||||
@@ -167,14 +167,14 @@ fn int128 __multi3(int128 a, int128 b) @extern("__multi3") @weak
|
||||
return r.all;
|
||||
}
|
||||
|
||||
fn float __floattisf(int128 a) @extern("__floattisf") @weak => float_from_i128(float, a);
|
||||
fn double __floattidf(int128 a) @extern("__floattidf") @weak => float_from_i128(double, a);
|
||||
fn float __floatuntisf(uint128 a) @extern("__floatuntisf") @weak => float_from_u128(float, a);
|
||||
fn double __floatuntidf(uint128 a) @extern("__floatuntidf") @weak => float_from_u128(double, a);
|
||||
fn uint128 __fixunsdfti(double a) @weak @extern("__fixunsdfti") => fixuint(a);
|
||||
fn uint128 __fixunssfti(float a) @weak @extern("__fixunssfti") => fixuint(a);
|
||||
fn int128 __fixdfti(double a) @weak @extern("__fixdfti") => fixint(a);
|
||||
fn int128 __fixsfti(float a) @weak @extern("__fixsfti") => fixint(a);
|
||||
fn float __floattisf(int128 a) @extern("__floattisf") @weak @nostrip => float_from_i128(float, a);
|
||||
fn double __floattidf(int128 a) @extern("__floattidf") @weak @nostrip => float_from_i128(double, a);
|
||||
fn float __floatuntisf(uint128 a) @extern("__floatuntisf") @weak @nostrip => float_from_u128(float, a);
|
||||
fn double __floatuntidf(uint128 a) @extern("__floatuntidf") @weak @nostrip => float_from_u128(double, a);
|
||||
fn uint128 __fixunsdfti(double a) @weak @extern("__fixunsdfti") @nostrip => fixuint(a);
|
||||
fn uint128 __fixunssfti(float a) @weak @extern("__fixunssfti") @nostrip => fixuint(a);
|
||||
fn int128 __fixdfti(double a) @weak @extern("__fixdfti") @nostrip => fixint(a);
|
||||
fn int128 __fixsfti(float a) @weak @extern("__fixsfti") @nostrip => fixint(a);
|
||||
|
||||
|
||||
macro float_from_i128($Type, a) @private
|
||||
|
||||
@@ -14,7 +14,7 @@ $if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
fn double __cos(double x, double y) @extern("__cos") @weak
|
||||
fn double __cos(double x, double y) @extern("__cos") @weak @nostrip
|
||||
{
|
||||
const C1 = 4.16666666666666019037e-02; /* 0x3FA55555, 0x5555554C */
|
||||
const C2 = -1.38888888888741095749e-03; /* 0xBF56C16C, 0x16C15177 */
|
||||
|
||||
@@ -24,7 +24,7 @@ const double C1 @private = 0x155553e1053a42.0p-57; /* 0.0416666233237390631894
|
||||
const double C2 @private = -0x16c087e80f1e27.0p-62; /* -0.00138867637746099294692 */
|
||||
const double C3 @private = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */
|
||||
|
||||
fn float __cosdf(double x) @extern("__cosdf") @weak
|
||||
fn float __cosdf(double x) @extern("__cosdf") @weak @nostrip
|
||||
{
|
||||
/* Try to optimize for parallel evaluation as in __tandf.c. */
|
||||
double z = x * x;
|
||||
|
||||
@@ -13,7 +13,7 @@ $if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
fn double __sin(double x, double y, int iy) @extern("__sin") @weak
|
||||
fn double __sin(double x, double y, int iy) @extern("__sin") @weak @nostrip
|
||||
{
|
||||
|
||||
const S1 = -1.66666666666666324348e-01; /* 0xBFC55555, 0x55555549 */
|
||||
|
||||
@@ -18,7 +18,7 @@ $if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
* ====================================================
|
||||
*/
|
||||
// |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]).
|
||||
fn float __sindf(double x) @extern("__sindf") @weak
|
||||
fn float __sindf(double x) @extern("__sindf") @weak @nostrip
|
||||
{
|
||||
const S1F = -0x15555554cbac77.0p-55; /* -0.166666666416265235595 */
|
||||
const S2F = 0x111110896efbb2.0p-59; /* 0.0083333293858894631756 */
|
||||
|
||||
@@ -29,7 +29,7 @@ const double[*] TAN_T = {
|
||||
2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */
|
||||
};
|
||||
|
||||
fn double __tan(double x, double y, int odd) @extern("__tan") @weak
|
||||
fn double __tan(double x, double y, int odd) @extern("__tan") @weak @nostrip
|
||||
{
|
||||
const double PIO4 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */
|
||||
const double PIO4LO = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */
|
||||
|
||||
@@ -27,7 +27,7 @@ const double[*] TANDF = {
|
||||
0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */
|
||||
};
|
||||
|
||||
fn float __tandf(double x, int odd) @extern("__tandf") @weak
|
||||
fn float __tandf(double x, int odd) @extern("__tandf") @weak @nostrip
|
||||
{
|
||||
double z = x * x;
|
||||
/*
|
||||
|
||||
@@ -30,7 +30,7 @@ const double[*] AT @private = {
|
||||
1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
|
||||
};
|
||||
|
||||
fn double _atan(double x) @weak @extern("atan")
|
||||
fn double _atan(double x) @weak @extern("atan") @nostrip
|
||||
{
|
||||
int id @noinit;
|
||||
uint ix = x.high_word();
|
||||
@@ -113,7 +113,7 @@ const float[*] ATF @private = {
|
||||
6.1687607318e-02,
|
||||
};
|
||||
|
||||
fn float _atanf(float x) @weak @extern("atanf")
|
||||
fn float _atanf(float x) @weak @extern("atanf") @nostrip
|
||||
{
|
||||
int id @noinit;
|
||||
uint ix = x.word();
|
||||
@@ -186,7 +186,7 @@ macro void extract_words(double d, uint* hi, uint* lo) @private
|
||||
*lo = (uint)rep;
|
||||
}
|
||||
|
||||
fn double _atan2(double y, double x) @weak @extern("atan2")
|
||||
fn double _atan2(double y, double x) @weak @extern("atan2") @nostrip
|
||||
{
|
||||
if (math::is_nan(x) || math::is_nan(y)) return x + y;
|
||||
|
||||
@@ -257,7 +257,7 @@ fn double _atan2(double y, double x) @weak @extern("atan2")
|
||||
const float PI_F @private = 3.1415927410e+00; /* 0x40490fdb */
|
||||
const float PI_LO_F @private = -8.7422776573e-08; /* 0xb3bbbd2e */
|
||||
|
||||
fn float _atan2f(float y, float x) @weak @extern("atan2f")
|
||||
fn float _atan2f(float y, float x) @weak @extern("atan2f") @nostrip
|
||||
{
|
||||
if (math::is_nan(x) || math::is_nan(y)) return x + y;
|
||||
uint ix = bitcast(x, uint);
|
||||
|
||||
@@ -2,7 +2,7 @@ module std::math::nolibc;
|
||||
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
|
||||
fn double _ceil(double x) @weak @extern("ceil")
|
||||
fn double _ceil(double x) @weak @extern("ceil") @nostrip
|
||||
{
|
||||
ulong ui = bitcast(x, ulong);
|
||||
int e = (int)((ui >> 52) & 0x7ff);
|
||||
@@ -19,7 +19,7 @@ fn double _ceil(double x) @weak @extern("ceil")
|
||||
}
|
||||
|
||||
|
||||
fn float _ceilf(float x) @weak @extern("ceilf")
|
||||
fn float _ceilf(float x) @weak @extern("ceilf") @nostrip
|
||||
{
|
||||
uint u = bitcast(x, uint);
|
||||
int e = (int)((u >> 23) & 0xff) - 0x7f;
|
||||
|
||||
@@ -2,7 +2,7 @@ module std::math::nolibc;
|
||||
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
|
||||
fn float _cosf(float x) @extern("cosf") @weak
|
||||
fn float _cosf(float x) @extern("cosf") @weak @nostrip
|
||||
{
|
||||
uint ix = bitcast(x, uint);
|
||||
uint sign = ix >> 31;
|
||||
@@ -54,7 +54,7 @@ fn float _cosf(float x) @extern("cosf") @weak
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
fn double _cos(double x) @extern("cos") @weak
|
||||
fn double _cos(double x) @extern("cos") @weak @nostrip
|
||||
{
|
||||
// High word of x.
|
||||
uint ix = (uint)(bitcast(x, ulong) >> 32);
|
||||
|
||||
@@ -5,7 +5,7 @@ $if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
macro uint _top12f(float x) @private => bitcast(x, uint) >> 20;
|
||||
|
||||
|
||||
fn float _exp2f(float x) @extern("exp2f") @weak
|
||||
fn float _exp2f(float x) @extern("exp2f") @weak @nostrip
|
||||
{
|
||||
double xd = x;
|
||||
uint abstop = _top12f(x) & 0x7ff;
|
||||
@@ -82,7 +82,7 @@ macro uint _top12d(double x) @private
|
||||
return (uint)(bitcast(x, ulong) >> 52);
|
||||
}
|
||||
|
||||
fn double _exp2(double x) @extern("exp2") @weak
|
||||
fn double _exp2(double x) @extern("exp2") @weak @nostrip
|
||||
{
|
||||
uint abstop = _top12d(x) & 0x7ff;
|
||||
ulong u = bitcast(x, ulong);
|
||||
|
||||
@@ -2,7 +2,7 @@ module std::math::nolibc;
|
||||
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
|
||||
fn double _floor(double x) @weak @extern("floor")
|
||||
fn double _floor(double x) @weak @extern("floor") @nostrip
|
||||
{
|
||||
ulong ui = bitcast(x, ulong);
|
||||
int e = (int)((ui >> 52) & 0x7ff);
|
||||
@@ -19,7 +19,7 @@ fn double _floor(double x) @weak @extern("floor")
|
||||
}
|
||||
|
||||
|
||||
fn float _floorf(float x) @weak @extern("floorf")
|
||||
fn float _floorf(float x) @weak @extern("floorf") @nostrip
|
||||
{
|
||||
uint u = bitcast(x, uint);
|
||||
int e = (int)((u >> 23) & 0xff) - 0x7f;
|
||||
|
||||
@@ -2,12 +2,12 @@ module std::math::nolibc;
|
||||
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
|
||||
fn float powf_broken(float x, float f) @extern("powf") @weak
|
||||
fn float powf_broken(float x, float f) @extern("powf") @weak @nostrip
|
||||
{
|
||||
unreachable("'powf' not supported");
|
||||
}
|
||||
|
||||
fn double pow_broken(double x, double y) @extern("pow") @weak
|
||||
fn double pow_broken(double x, double y) @extern("pow") @weak @nostrip
|
||||
{
|
||||
unreachable("'pow' not supported");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ module std::math::nolibc;
|
||||
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
|
||||
fn double _round(double x) @extern("round") @weak
|
||||
fn double _round(double x) @extern("round") @weak @nostrip
|
||||
{
|
||||
ulong u = bitcast(x, ulong);
|
||||
int e = (int)((u >> 52) & 0x7ff);
|
||||
@@ -28,7 +28,7 @@ fn double _round(double x) @extern("round") @weak
|
||||
return y;
|
||||
}
|
||||
|
||||
fn float _roundf(float x) @extern("roundf") @weak
|
||||
fn float _roundf(float x) @extern("roundf") @weak @nostrip
|
||||
{
|
||||
uint u = bitcast(x, uint);
|
||||
int e = (u >> 23) & 0xff;
|
||||
|
||||
@@ -2,7 +2,7 @@ module std::math::nolibc;
|
||||
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
|
||||
fn double _scalbn(double x, int n) @weak @extern("scalbn")
|
||||
fn double _scalbn(double x, int n) @weak @extern("scalbn") @nostrip
|
||||
{
|
||||
switch
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ $if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
fn float _sinf(float x) @weak @extern("sinf")
|
||||
fn float _sinf(float x) @weak @extern("sinf") @nostrip
|
||||
{
|
||||
uint ix = bitcast(x, uint);
|
||||
int sign = ix >> 31;
|
||||
@@ -87,7 +87,7 @@ fn float _sinf(float x) @weak @extern("sinf")
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
fn double sin(double x) @extern("sin") @weak
|
||||
fn double sin(double x) @extern("sin") @weak @nostrip
|
||||
{
|
||||
// High word of x.
|
||||
uint ix = (uint)(bitcast(x, ulong) >> 32);
|
||||
|
||||
@@ -18,7 +18,7 @@ $if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
fn void sincosf(float x, float *sin, float *cos) @extern("sincosf") @weak
|
||||
fn void sincosf(float x, float *sin, float *cos) @extern("sincosf") @weak @nostrip
|
||||
{
|
||||
|
||||
uint ix = bitcast(x, uint);
|
||||
@@ -107,7 +107,7 @@ fn void sincosf(float x, float *sin, float *cos) @extern("sincosf") @weak
|
||||
|
||||
}
|
||||
|
||||
fn void sincos(double x, double *sin, double *cos) @extern("sincos") @weak
|
||||
fn void sincos(double x, double *sin, double *cos) @extern("sincos") @weak @nostrip
|
||||
{
|
||||
// High word of x.
|
||||
uint ix = (uint)(bitcast(x, ulong) >> 32);
|
||||
|
||||
@@ -14,7 +14,7 @@ $if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
fn double tan(double x) @extern("tan") @weak
|
||||
fn double tan(double x) @extern("tan") @weak @nostrip
|
||||
{
|
||||
uint ix = (uint)(bitcast(x, ulong) >> 32);
|
||||
ix &= 0x7fffffff;
|
||||
@@ -59,7 +59,7 @@ fn double tan(double x) @extern("tan") @weak
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
fn float tanf(float x) @extern("tanf") @weak
|
||||
fn float tanf(float x) @extern("tanf") @weak @nostrip
|
||||
{
|
||||
uint ix = bitcast(x, uint);
|
||||
uint sign = ix >> 31;
|
||||
|
||||
@@ -2,7 +2,7 @@ module std::math::nolibc::trig;
|
||||
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
|
||||
fn double sincos_broken(double x) @extern("sincos") @weak
|
||||
fn double sincos_broken(double x) @extern("sincos") @weak @nostrip
|
||||
{
|
||||
unreachable("'sinccos' not supported");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ module std::math::nolibc;
|
||||
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE):
|
||||
|
||||
fn double _trunc(double x) @weak @extern("trunc")
|
||||
fn double _trunc(double x) @weak @extern("trunc") @nostrip
|
||||
{
|
||||
ulong i = bitcast(x, ulong);
|
||||
int e = (int)((i >> 52) & 0x7ff) - 0x3ff + 12;
|
||||
@@ -15,7 +15,7 @@ fn double _trunc(double x) @weak @extern("trunc")
|
||||
return bitcast(i, double);
|
||||
}
|
||||
|
||||
fn float _truncf(float x) @weak @extern("truncf")
|
||||
fn float _truncf(float x) @weak @extern("truncf") @nostrip
|
||||
{
|
||||
uint i = bitcast(x, uint);
|
||||
int e = (int)((i >> 23) & 0xff) - 0x7f + 9;
|
||||
|
||||
@@ -133,6 +133,7 @@ static void usage(void)
|
||||
OUTPUT(" --x86vec=<option> - Set max level of vector instructions: none, native, mmx, sse, avx, avx512.");
|
||||
OUTPUT(" --riscvfloat=<option> - Set type of RISC-V float support: none, float, double");
|
||||
OUTPUT(" --memory-env=<option> - Set the memory environment: normal, small, tiny, none.");
|
||||
OUTPUT(" --strip-unused - Strip unused code and globals from the output (experimental)");
|
||||
OUTPUT("");
|
||||
OUTPUT(" --debug-stats - Print debug statistics.");
|
||||
#ifndef NDEBUG
|
||||
@@ -543,6 +544,11 @@ static void parse_option(BuildOptions *options)
|
||||
print_version();
|
||||
exit_compiler(COMPILER_SUCCESS_EXIT);
|
||||
}
|
||||
if (match_longopt("strip-unused"))
|
||||
{
|
||||
options->strip_unused = true;
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("x86vec")))
|
||||
{
|
||||
options->x86_vector_capability = (X86VectorCapability)parse_multi_option(argopt, 6, vector_capability);
|
||||
|
||||
@@ -318,6 +318,7 @@ typedef struct BuildOptions_
|
||||
X86VectorCapability x86_vector_capability;
|
||||
RiscvFloatCapability riscv_float_capability;
|
||||
MemoryEnvironment memory_environment;
|
||||
bool strip_unused;
|
||||
bool print_keywords;
|
||||
bool print_attributes;
|
||||
bool print_builtins;
|
||||
@@ -390,6 +391,7 @@ typedef struct
|
||||
bool emit_asm;
|
||||
bool no_stdlib;
|
||||
bool no_libc;
|
||||
bool strip_unused;
|
||||
bool emit_object_files;
|
||||
bool force_linker;
|
||||
bool benchmarking;
|
||||
|
||||
@@ -199,6 +199,8 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
{
|
||||
target->feature.safe_mode = options->safe_mode == 1;
|
||||
}
|
||||
if (options->strip_unused) target->strip_unused = true;
|
||||
|
||||
if (options->memory_environment != MEMORY_ENV_NOT_SET)
|
||||
{
|
||||
target->memory_environment = options->memory_environment;
|
||||
|
||||
@@ -676,6 +676,8 @@ typedef struct Decl_
|
||||
bool is_dynamic : 1;
|
||||
bool is_synthetic : 1;
|
||||
bool is_export : 1;
|
||||
bool is_live : 1;
|
||||
bool no_strip : 1;
|
||||
OperatorOverload operator : 4;
|
||||
union
|
||||
{
|
||||
|
||||
@@ -339,8 +339,23 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
MACRO_COPY_EXPR(expr->ct_call_expr.main_var);
|
||||
return expr;
|
||||
case EXPR_TRY_UNWRAP:
|
||||
if (expr->resolve_status != RESOLVE_DONE)
|
||||
{
|
||||
MACRO_COPY_EXPR(expr->try_unwrap_expr.init);
|
||||
MACRO_COPY_TYPE(expr->try_unwrap_expr.type);
|
||||
}
|
||||
else
|
||||
{
|
||||
MACRO_COPY_EXPR(expr->try_unwrap_expr.optional);
|
||||
if (expr->try_unwrap_expr.assign_existing)
|
||||
{
|
||||
MACRO_COPY_EXPR(expr->try_unwrap_expr.lhs);
|
||||
}
|
||||
else
|
||||
{
|
||||
MACRO_COPY_DECL(expr->try_unwrap_expr.decl);
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
MACRO_COPY_EXPR_LIST(expr->try_unwrap_chain_expr);
|
||||
|
||||
@@ -167,7 +167,8 @@ typedef enum
|
||||
case DECL_FINALIZE: case DECL_CT_ECHO: case DECL_CT_INCLUDE: case DECL_GLOBALS
|
||||
|
||||
#define NON_RUNTIME_EXPR EXPR_DESIGNATOR: case EXPR_POISONED: \
|
||||
case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \
|
||||
case EXPR_CT_CHECKS: \
|
||||
case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \
|
||||
case EXPR_COMPILER_CONST: case EXPR_CT_CALL: case EXPR_FLATPATH: \
|
||||
case EXPR_VARIANTSWITCH: case EXPR_STRINGIFY: case EXPR_CT_EVAL
|
||||
|
||||
@@ -774,6 +775,7 @@ typedef enum
|
||||
ATTRIBUTE_NOINIT,
|
||||
ATTRIBUTE_NOINLINE,
|
||||
ATTRIBUTE_NORETURN,
|
||||
ATTRIBUTE_NOSTRIP,
|
||||
ATTRIBUTE_OBFUSCATE,
|
||||
ATTRIBUTE_OPERATOR,
|
||||
ATTRIBUTE_OVERLAP,
|
||||
|
||||
@@ -612,6 +612,7 @@ static void append_fpie_pic_options(RelocModel reloc, const char ***args_ref)
|
||||
|
||||
LinkerType linker_find_linker_type(void)
|
||||
{
|
||||
if (arch_is_wasm(platform_target.arch)) return LINKER_WASM;
|
||||
switch (platform_target.os)
|
||||
{
|
||||
case OS_UNSUPPORTED:
|
||||
|
||||
@@ -1244,10 +1244,13 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
{
|
||||
if (!vec_size(module->units)) return NULL;
|
||||
assert(intrinsics_setup);
|
||||
|
||||
bool has_elements = false;
|
||||
GenContext *gen_context = cmalloc(sizeof(GenContext));
|
||||
gencontext_init(gen_context, module, shared_context);
|
||||
gencontext_begin_module(gen_context);
|
||||
|
||||
bool only_used = active_target.strip_unused && !active_target.testing;
|
||||
FOREACH_BEGIN(CompilationUnit *unit, module->units)
|
||||
|
||||
gencontext_init_file_emit(gen_context, unit);
|
||||
@@ -1255,10 +1258,12 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
gen_context->debug.file = unit->llvm.debug_file;
|
||||
|
||||
FOREACH_BEGIN(Decl *initializer, unit->xxlizers)
|
||||
has_elements = true;
|
||||
llvm_emit_xxlizer(gen_context, initializer);
|
||||
FOREACH_END();
|
||||
|
||||
FOREACH_BEGIN(Decl *method, unit->methods)
|
||||
if (only_used && !method->is_live) continue;
|
||||
llvm_emit_function_decl(gen_context, method);
|
||||
FOREACH_END();
|
||||
|
||||
@@ -1271,6 +1276,7 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
FOREACH_END();
|
||||
|
||||
FOREACH_BEGIN(Decl *func, unit->functions)
|
||||
if (only_used && !func->is_live) continue;
|
||||
if (func->func_decl.attr_test)
|
||||
{
|
||||
if (!active_target.testing) continue;
|
||||
@@ -1280,11 +1286,14 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
FOREACH_END();
|
||||
|
||||
FOREACH_BEGIN(Decl *func, unit->lambdas)
|
||||
if (only_used && !func->is_live) continue;
|
||||
has_elements = true;
|
||||
llvm_emit_function_decl(gen_context, func);
|
||||
FOREACH_END();
|
||||
|
||||
if (active_target.type != TARGET_TYPE_TEST && unit->main_function && unit->main_function->is_synthetic)
|
||||
{
|
||||
has_elements = true;
|
||||
llvm_emit_function_decl(gen_context, unit->main_function);
|
||||
}
|
||||
|
||||
@@ -1296,29 +1305,44 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
gen_context->debug.file = unit->llvm.debug_file;
|
||||
|
||||
FOREACH_BEGIN(Decl *var, unit->vars)
|
||||
if (only_used && !var->is_live) continue;
|
||||
has_elements = true;
|
||||
llvm_get_ref(gen_context, var);
|
||||
FOREACH_END();
|
||||
|
||||
FOREACH_BEGIN(Decl *var, unit->vars)
|
||||
if (only_used && !var->is_live) continue;
|
||||
has_elements = true;
|
||||
llvm_emit_global_variable_init(gen_context, var);
|
||||
FOREACH_END();
|
||||
|
||||
FOREACH_BEGIN(Decl *decl, unit->functions)
|
||||
if (decl->func_decl.attr_test && !active_target.testing) continue;
|
||||
if (decl->func_decl.body) llvm_emit_function_body(gen_context, decl);
|
||||
if (only_used && !decl->is_live) continue;
|
||||
if (decl->func_decl.body)
|
||||
{
|
||||
has_elements = true;
|
||||
llvm_emit_function_body(gen_context, decl);
|
||||
}
|
||||
FOREACH_END();
|
||||
|
||||
FOREACH_BEGIN(Decl *func, unit->lambdas)
|
||||
if (only_used && !func->is_live) continue;
|
||||
has_elements = true;
|
||||
llvm_emit_function_body(gen_context, func);
|
||||
FOREACH_END();
|
||||
|
||||
if (active_target.type != TARGET_TYPE_TEST && unit->main_function && unit->main_function->is_synthetic)
|
||||
{
|
||||
has_elements = true;
|
||||
llvm_emit_function_body(gen_context, unit->main_function);
|
||||
}
|
||||
|
||||
FOREACH_BEGIN(Decl *decl, unit->methods)
|
||||
if (decl->func_decl.body) llvm_emit_function_body(gen_context, decl);
|
||||
if (only_used && !decl->is_live) continue;
|
||||
if (!decl->func_decl.body) continue;
|
||||
has_elements = true;
|
||||
llvm_emit_function_body(gen_context, decl);
|
||||
FOREACH_END();
|
||||
|
||||
gencontext_end_file_emit(gen_context, unit);
|
||||
@@ -1341,6 +1365,7 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
gencontext_print_llvm_ir(gen_context);
|
||||
gencontext_verify_ir(gen_context);
|
||||
}
|
||||
if (!has_elements) return NULL;
|
||||
return gen_context;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ static inline LLVMValueRef llvm_const_low_bitmask(GenContext *c, LLVMTypeRef typ
|
||||
static inline LLVMValueRef llvm_emit_expr_to_rvalue(GenContext *c, Expr *expr);
|
||||
static inline LLVMValueRef llvm_emit_exprid_to_rvalue(GenContext *c, ExprId expr_id);
|
||||
static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, MemberIndex index);
|
||||
static inline void gencontext_emit_expression_list_expr(GenContext *context, BEValue *be_value, Expr *expr);
|
||||
static inline void llvm_emit_expression_list_expr(GenContext *c, BEValue *be_value, Expr *expr);
|
||||
|
||||
static inline void llvm_emit_bitassign_array(GenContext *c, BEValue *result, BEValue parent, Decl *parent_decl, Decl *member);
|
||||
static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr);
|
||||
@@ -5431,11 +5431,11 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
|
||||
|
||||
|
||||
|
||||
static inline void gencontext_emit_expression_list_expr(GenContext *context, BEValue *be_value, Expr *expr)
|
||||
static inline void llvm_emit_expression_list_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
VECEACH(expr->expression_list, i)
|
||||
{
|
||||
llvm_emit_expr(context, be_value, expr->expression_list[i]);
|
||||
llvm_emit_expr(c, be_value, expr->expression_list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6138,10 +6138,8 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
case NON_RUNTIME_EXPR:
|
||||
case EXPR_COND:
|
||||
case EXPR_CT_ARG:
|
||||
case EXPR_ASM:
|
||||
case EXPR_VASPLAT:
|
||||
case EXPR_CT_CHECKS:
|
||||
UNREACHABLE
|
||||
case EXPR_LAMBDA:
|
||||
llvm_emit_lambda(c, value, expr);
|
||||
@@ -6261,7 +6259,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
llvm_emit_call_expr(c, value, expr, NULL);
|
||||
return;
|
||||
case EXPR_EXPRESSION_LIST:
|
||||
gencontext_emit_expression_list_expr(c, value, expr);
|
||||
llvm_emit_expression_list_expr(c, value, expr);
|
||||
return;
|
||||
case EXPR_CAST:
|
||||
llvm_emit_cast_expr(c, value, expr);
|
||||
|
||||
@@ -867,7 +867,7 @@ static void llvm_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *swi
|
||||
void gencontext_emit_switch(GenContext *context, Ast *ast)
|
||||
{
|
||||
BEValue switch_value;
|
||||
llvm_emit_decl_expr_list(context, &switch_value, exprptr(ast->switch_stmt.cond), false);
|
||||
llvm_emit_decl_expr_list(context, &switch_value, exprptrzero(ast->switch_stmt.cond), false);
|
||||
llvm_emit_switch_body(context, &switch_value, ast);
|
||||
}
|
||||
|
||||
@@ -1192,7 +1192,6 @@ static inline void llvm_emit_asm_block_stmt(GenContext *c, Ast *ast)
|
||||
/* can throw */ false
|
||||
);
|
||||
LLVMValueRef res = LLVMBuildCall2(c->builder, asm_fn_type, asm_fn, args, param_count, "");
|
||||
#if LLVM_VERSION_MAJOR > 13
|
||||
for (unsigned i = 0; i < param_count; i++)
|
||||
{
|
||||
if (pointer_type[i])
|
||||
@@ -1200,9 +1199,6 @@ static inline void llvm_emit_asm_block_stmt(GenContext *c, Ast *ast)
|
||||
llvm_attribute_add_call_type(c, res, attribute_id.elementtype, i + 1, pointer_type[i]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)pointer_type;
|
||||
#endif
|
||||
if (!result_count) return;
|
||||
if (result_count == 1)
|
||||
{
|
||||
|
||||
@@ -1458,6 +1458,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
||||
[ATTRIBUTE_BUILTIN] = ATTR_MACRO | ATTR_FUNC,
|
||||
[ATTRIBUTE_CDECL] = ATTR_FUNC,
|
||||
[ATTRIBUTE_EXPORT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES,
|
||||
[ATTRIBUTE_NOSTRIP] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES,
|
||||
[ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_DEFINE | ATTR_MACRO | ATTR_XXLIZER),
|
||||
[ATTRIBUTE_EXTERN] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_DEFINE | ATTR_MACRO | ATTR_XXLIZER),
|
||||
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
|
||||
@@ -1629,6 +1630,9 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
||||
}
|
||||
decl->is_export = true;
|
||||
return true;
|
||||
case ATTRIBUTE_NOSTRIP:
|
||||
decl->no_strip = true;
|
||||
return true;
|
||||
case ATTRIBUTE_SECTION:
|
||||
case ATTRIBUTE_EXTERN:
|
||||
case ATTRIBUTE_EXTNAME:
|
||||
|
||||
@@ -80,6 +80,7 @@ void sema_analysis_pass_functions(Module *module);
|
||||
|
||||
void sema_analysis_pass_lambda(Module *module);
|
||||
void sema_analyze_stage(Module *module, AnalysisStage stage);
|
||||
void sema_trace_liveness(void);
|
||||
|
||||
bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr);
|
||||
bool sema_analyse_expr_lvalue_fold_const(SemaContext *context, Expr *expr);
|
||||
|
||||
527
src/compiler/sema_liveness.c
Normal file
527
src/compiler/sema_liveness.c
Normal file
@@ -0,0 +1,527 @@
|
||||
// Copyright (c) 2023 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by a LGPLv3.0
|
||||
// a copy of which can be found in the LICENSE file.
|
||||
|
||||
#include "sema_internal.h"
|
||||
|
||||
static void sema_trace_expr_liveness(Expr *expr);
|
||||
static void sema_trace_stmt_liveness(Ast *ast);
|
||||
static void sema_trace_decl_liveness(Decl *decl);
|
||||
|
||||
INLINE void sema_trace_exprid_liveness(ExprId expr)
|
||||
{
|
||||
if (expr) sema_trace_expr_liveness(exprptr(expr));
|
||||
}
|
||||
|
||||
INLINE void sema_trace_astid_liveness(AstId astid)
|
||||
{
|
||||
if (astid) sema_trace_stmt_liveness(astptr(astid));
|
||||
}
|
||||
|
||||
static void sema_trace_expr_list_liveness(Expr **exprlist)
|
||||
{
|
||||
FOREACH_BEGIN(Expr *arg, exprlist)
|
||||
sema_trace_expr_liveness(arg);
|
||||
FOREACH_END();
|
||||
}
|
||||
|
||||
static void sema_trace_stmt_chain_liveness(AstId astid)
|
||||
{
|
||||
AstId current = astid;
|
||||
while (current)
|
||||
{
|
||||
Ast *stmt = ast_next(¤t);
|
||||
sema_trace_stmt_liveness(stmt);
|
||||
switch (stmt->ast_kind)
|
||||
{
|
||||
case AST_RETURN_STMT:
|
||||
case AST_BREAK_STMT:
|
||||
case AST_CONTINUE_STMT:
|
||||
case AST_NEXT_STMT:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
REMINDER("Optimize to ignore after return");
|
||||
return;
|
||||
}
|
||||
static void sema_trace_asm_arg_list(ExprAsmArg **list)
|
||||
{
|
||||
FOREACH_BEGIN(ExprAsmArg *asm_arg, list)
|
||||
switch (asm_arg->kind)
|
||||
{
|
||||
case ASM_ARG_ADDR:
|
||||
case ASM_ARG_ADDROF:
|
||||
TODO
|
||||
case ASM_ARG_REG:
|
||||
case ASM_ARG_INT:
|
||||
continue;
|
||||
case ASM_ARG_MEMVAR:
|
||||
case ASM_ARG_REGVAR:
|
||||
sema_trace_decl_liveness(asm_arg->ident.ident_decl);
|
||||
continue;
|
||||
case ASM_ARG_VALUE:
|
||||
sema_trace_exprid_liveness(asm_arg->expr_id);
|
||||
continue;
|
||||
}
|
||||
UNREACHABLE
|
||||
FOREACH_END();
|
||||
}
|
||||
|
||||
static void sema_trace_stmt_liveness(Ast *ast)
|
||||
{
|
||||
if (!ast) return;
|
||||
switch (ast->ast_kind)
|
||||
{
|
||||
case AST_POISONED:
|
||||
case AST_CT_ECHO_STMT:
|
||||
case AST_CT_ELSE_STMT:
|
||||
case AST_CT_FOREACH_STMT:
|
||||
case AST_CT_FOR_STMT:
|
||||
case AST_CT_IF_STMT:
|
||||
case AST_CT_ASSERT:
|
||||
case AST_CT_SWITCH_STMT:
|
||||
case AST_DOC_STMT:
|
||||
case AST_FOREACH_STMT:
|
||||
UNREACHABLE
|
||||
case AST_ASM_STMT:
|
||||
sema_trace_expr_list_liveness(ast->asm_stmt.args);
|
||||
return;
|
||||
case AST_DEFER_STMT:
|
||||
case AST_NOP_STMT:
|
||||
return;
|
||||
case AST_COMPOUND_STMT:
|
||||
sema_trace_stmt_chain_liveness(ast->compound_stmt.first_stmt);
|
||||
return;
|
||||
case AST_EXPR_STMT:
|
||||
sema_trace_expr_liveness(ast->expr_stmt);
|
||||
return;
|
||||
case AST_DECLARE_STMT:
|
||||
sema_trace_decl_liveness(ast->declare_stmt);
|
||||
return;
|
||||
case AST_RETURN_STMT:
|
||||
case AST_BLOCK_EXIT_STMT:
|
||||
sema_trace_expr_liveness(ast->return_stmt.expr);
|
||||
sema_trace_astid_liveness(ast->return_stmt.cleanup);
|
||||
return;
|
||||
case AST_ASM_BLOCK_STMT:
|
||||
if (ast->asm_block_stmt.is_string)
|
||||
{
|
||||
sema_trace_exprid_liveness(ast->asm_block_stmt.asm_string);
|
||||
return;
|
||||
}
|
||||
sema_trace_stmt_chain_liveness(ast->asm_block_stmt.block->asm_stmt);
|
||||
sema_trace_asm_arg_list(ast->asm_block_stmt.block->input);
|
||||
sema_trace_asm_arg_list(ast->asm_block_stmt.block->output_vars);
|
||||
return;
|
||||
case AST_ASSERT_STMT:
|
||||
{
|
||||
Expr *e = exprptr(ast->assert_stmt.expr);
|
||||
if (active_target.feature.safe_mode || expr_is_pure(e))
|
||||
{
|
||||
sema_trace_expr_liveness(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case AST_DECLS_STMT:
|
||||
{
|
||||
FOREACH_BEGIN(Decl *decl, ast->decls_stmt)
|
||||
sema_trace_decl_liveness(decl);
|
||||
FOREACH_END();
|
||||
return;
|
||||
}
|
||||
case AST_FOR_STMT:
|
||||
sema_trace_exprid_liveness(ast->for_stmt.cond);
|
||||
sema_trace_exprid_liveness(ast->for_stmt.init);
|
||||
sema_trace_exprid_liveness(ast->for_stmt.incr);
|
||||
sema_trace_astid_liveness(ast->for_stmt.body);
|
||||
return;
|
||||
case AST_IF_STMT:
|
||||
sema_trace_exprid_liveness(ast->if_stmt.cond);
|
||||
sema_trace_astid_liveness(ast->if_stmt.then_body);
|
||||
sema_trace_astid_liveness(ast->if_stmt.else_body);
|
||||
return;
|
||||
case AST_SWITCH_STMT:
|
||||
case AST_IF_CATCH_SWITCH_STMT:
|
||||
sema_trace_exprid_liveness(ast->switch_stmt.cond);
|
||||
{
|
||||
FOREACH_BEGIN(Ast *casestm, ast->switch_stmt.cases)
|
||||
sema_trace_stmt_liveness(casestm);
|
||||
FOREACH_END();
|
||||
}
|
||||
return;
|
||||
case AST_CASE_STMT:
|
||||
sema_trace_expr_liveness(ast->case_stmt.expr);
|
||||
sema_trace_expr_liveness(ast->case_stmt.to_expr);
|
||||
sema_trace_stmt_liveness(ast->case_stmt.body);
|
||||
return;
|
||||
case AST_DEFAULT_STMT:
|
||||
sema_trace_stmt_liveness(ast->case_stmt.body);
|
||||
return;
|
||||
case AST_NEXT_STMT:
|
||||
sema_trace_stmt_chain_liveness(ast->nextcase_stmt.defer_id);
|
||||
sema_trace_expr_liveness(ast->nextcase_stmt.switch_expr);
|
||||
return;
|
||||
case AST_BREAK_STMT:
|
||||
case AST_CONTINUE_STMT:
|
||||
sema_trace_stmt_chain_liveness(ast->contbreak_stmt.defers);
|
||||
return;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static void sema_trace_const_initializer_liveness(ConstInitializer *const_init)
|
||||
{
|
||||
switch (const_init->kind)
|
||||
{
|
||||
case CONST_INIT_ZERO:
|
||||
return;
|
||||
case CONST_INIT_ARRAY_VALUE:
|
||||
UNREACHABLE
|
||||
case CONST_INIT_ARRAY_FULL:
|
||||
{
|
||||
bool was_modified = false;
|
||||
Type *array_type = const_init->type;
|
||||
ConstInitializer **elements = const_init->init_array_full;
|
||||
ArraySize size = array_type->array.len;
|
||||
for (MemberIndex i = 0; i < (MemberIndex)size; i++)
|
||||
{
|
||||
sema_trace_const_initializer_liveness(elements[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case CONST_INIT_ARRAY:
|
||||
{
|
||||
FOREACH_BEGIN(ConstInitializer *i, const_init->init_array.elements)
|
||||
sema_trace_const_initializer_liveness(i);
|
||||
FOREACH_END();
|
||||
return;
|
||||
}
|
||||
case CONST_INIT_UNION:
|
||||
sema_trace_const_initializer_liveness(const_init->init_union.element);
|
||||
return;
|
||||
case CONST_INIT_STRUCT:
|
||||
{
|
||||
Decl *decl = const_init->type->decl;
|
||||
Decl **members = decl->strukt.members;
|
||||
uint32_t count = vec_size(members);
|
||||
if (decl->decl_kind == DECL_UNION && count) count = 1;
|
||||
for (MemberIndex i = 0; i < count; i++)
|
||||
{
|
||||
sema_trace_const_initializer_liveness(const_init->init_struct[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case CONST_INIT_VALUE:
|
||||
sema_trace_expr_liveness(const_init->init_value);
|
||||
return;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
static void sema_trace_expr_liveness(Expr *expr)
|
||||
{
|
||||
RETRY:
|
||||
if (!expr) return;
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
case EXPR_GROUP:
|
||||
case EXPR_BUILTIN:
|
||||
case EXPR_OPERATOR_CHARS:
|
||||
case EXPR_VASPLAT:
|
||||
case EXPR_POISONED:
|
||||
case EXPR_COMPILER_CONST:
|
||||
case EXPR_CT_ARG:
|
||||
case EXPR_CT_CALL:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_CT_IDENT:
|
||||
case EXPR_VARIANTSWITCH:
|
||||
UNREACHABLE
|
||||
case EXPR_DESIGNATOR:
|
||||
sema_trace_expr_liveness(expr->designator_expr.value);
|
||||
return;
|
||||
case EXPR_FLATPATH:
|
||||
case EXPR_HASH_IDENT:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_TYPEINFO:
|
||||
return;
|
||||
case EXPR_ACCESS:
|
||||
case EXPR_BITACCESS:
|
||||
sema_trace_decl_liveness(expr->access_expr.ref);
|
||||
expr = expr->access_expr.parent;
|
||||
goto RETRY;
|
||||
case EXPR_ASM:
|
||||
switch (expr->expr_asm_arg.kind)
|
||||
{
|
||||
case ASM_ARG_REG:
|
||||
case ASM_ARG_ADDROF:
|
||||
case ASM_ARG_REGVAR:
|
||||
case ASM_ARG_INT:
|
||||
case ASM_ARG_MEMVAR:
|
||||
return;
|
||||
case ASM_ARG_VALUE:
|
||||
case ASM_ARG_ADDR:
|
||||
sema_trace_expr_liveness(exprptr(expr->expr_asm_arg.expr_id));
|
||||
return;
|
||||
}
|
||||
UNREACHABLE
|
||||
case EXPR_BINARY:
|
||||
case EXPR_BITASSIGN:
|
||||
sema_trace_expr_liveness(exprptr(expr->binary_expr.left));
|
||||
sema_trace_expr_liveness(exprptr(expr->binary_expr.right));
|
||||
return;
|
||||
case EXPR_CALL:
|
||||
{
|
||||
sema_trace_expr_list_liveness(expr->call_expr.arguments);
|
||||
if (expr->call_expr.varargs)
|
||||
{
|
||||
if (expr->call_expr.splat_vararg)
|
||||
{
|
||||
sema_trace_expr_liveness(expr->call_expr.splat);
|
||||
}
|
||||
else
|
||||
{
|
||||
sema_trace_expr_list_liveness(expr->call_expr.varargs);
|
||||
}
|
||||
}
|
||||
if (expr->call_expr.is_builtin) return;
|
||||
if (!expr->call_expr.is_func_ref)
|
||||
{
|
||||
sema_trace_expr_liveness(exprptr(expr->call_expr.function));
|
||||
return;
|
||||
}
|
||||
sema_trace_decl_liveness(declptr(expr->call_expr.func_ref));
|
||||
return;
|
||||
}
|
||||
case EXPR_CAST:
|
||||
expr = exprptr(expr->cast_expr.expr);
|
||||
goto RETRY;
|
||||
case EXPR_CATCH:
|
||||
case EXPR_FORCE_UNWRAP:
|
||||
case EXPR_RETHROW:
|
||||
case EXPR_OPTIONAL:
|
||||
case EXPR_TRY:
|
||||
expr = expr->inner_expr;
|
||||
goto RETRY;
|
||||
case EXPR_BUILTIN_ACCESS:
|
||||
expr = exprptr(expr->builtin_access_expr.inner);
|
||||
goto RETRY;
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
{
|
||||
if (expr->catch_unwrap_expr.lhs)
|
||||
{
|
||||
sema_trace_expr_liveness(expr->catch_unwrap_expr.lhs);
|
||||
}
|
||||
else if (expr->catch_unwrap_expr.decl)
|
||||
{
|
||||
sema_trace_decl_liveness(expr->catch_unwrap_expr.decl);
|
||||
}
|
||||
FOREACH_BEGIN(Expr *e, expr->catch_unwrap_expr.exprs)
|
||||
sema_trace_expr_liveness(e);
|
||||
FOREACH_END();
|
||||
return;
|
||||
}
|
||||
case EXPR_CONST:
|
||||
if (expr->const_expr.const_kind != CONST_INITIALIZER) return;
|
||||
{
|
||||
sema_trace_const_initializer_liveness(expr->const_expr.initializer);
|
||||
}
|
||||
return;
|
||||
case EXPR_COMPOUND_LITERAL:
|
||||
sema_trace_expr_liveness(expr->expr_compound_literal.initializer);
|
||||
return;
|
||||
case EXPR_COND:
|
||||
{
|
||||
FOREACH_BEGIN(Expr *e, expr->cond_expr)
|
||||
sema_trace_expr_liveness(e);
|
||||
FOREACH_END();
|
||||
return;
|
||||
}
|
||||
case EXPR_DECL:
|
||||
sema_trace_decl_liveness(expr->decl_expr);
|
||||
return;
|
||||
case EXPR_EXPRESSION_LIST:
|
||||
sema_trace_expr_list_liveness(expr->expression_list);
|
||||
return;
|
||||
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
||||
sema_trace_expr_list_liveness(expr->designated_init_list);
|
||||
return;
|
||||
case EXPR_EXPR_BLOCK:
|
||||
sema_trace_stmt_liveness(astptr(expr->expr_block.first_stmt));
|
||||
return;
|
||||
case EXPR_IDENTIFIER:
|
||||
sema_trace_decl_liveness(expr->identifier_expr.decl);
|
||||
return;
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
{
|
||||
FOREACH_BEGIN(Expr *e, expr->initializer_list)
|
||||
sema_trace_expr_liveness(e);
|
||||
FOREACH_END();
|
||||
return;
|
||||
}
|
||||
case EXPR_LAMBDA:
|
||||
sema_trace_decl_liveness(expr->lambda_expr);
|
||||
return;
|
||||
case EXPR_MACRO_BLOCK:
|
||||
{
|
||||
FOREACH_BEGIN(Decl *val, expr->macro_block.params)
|
||||
sema_trace_decl_liveness(val);
|
||||
FOREACH_END();
|
||||
sema_trace_stmt_chain_liveness(expr->macro_block.first_stmt);
|
||||
return;
|
||||
}
|
||||
case EXPR_MACRO_BODY_EXPANSION:
|
||||
sema_trace_stmt_liveness(astptrzero(expr->body_expansion_expr.first_stmt));
|
||||
return;
|
||||
case EXPR_NOP:
|
||||
return;
|
||||
case EXPR_POINTER_OFFSET:
|
||||
sema_trace_expr_liveness(exprptr(expr->pointer_offset_expr.ptr));
|
||||
expr = exprptr(expr->pointer_offset_expr.offset);
|
||||
goto RETRY;
|
||||
case EXPR_POST_UNARY:
|
||||
case EXPR_UNARY:
|
||||
expr = expr->unary_expr.expr;
|
||||
goto RETRY;
|
||||
case EXPR_RETVAL:
|
||||
return;
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_SLICE_COPY:
|
||||
sema_trace_expr_liveness(exprptr(expr->slice_assign_expr.left));
|
||||
sema_trace_expr_liveness(exprptr(expr->slice_assign_expr.right));
|
||||
return;
|
||||
case EXPR_SLICE:
|
||||
case EXPR_SUBSCRIPT:
|
||||
case EXPR_SUBSCRIPT_ADDR:
|
||||
sema_trace_expr_liveness(exprptr(expr->subscript_expr.expr));
|
||||
sema_trace_expr_liveness(exprptr(expr->subscript_expr.range.start));
|
||||
sema_trace_expr_liveness(exprptrzero(expr->subscript_expr.range.end));
|
||||
return;
|
||||
case EXPR_SWIZZLE:
|
||||
sema_trace_expr_liveness(exprptr(expr->swizzle_expr.parent));
|
||||
return;
|
||||
case EXPR_TERNARY:
|
||||
{
|
||||
REMINDER("Tracing ternary can be optimized");
|
||||
sema_trace_expr_liveness(exprptr(expr->ternary_expr.cond));
|
||||
if (expr->ternary_expr.then_expr)
|
||||
{
|
||||
sema_trace_expr_liveness(exprptr(expr->ternary_expr.then_expr));
|
||||
}
|
||||
expr = exprptr(expr->ternary_expr.else_expr);
|
||||
goto RETRY;
|
||||
}
|
||||
case EXPR_TEST_HOOK:
|
||||
return;
|
||||
case EXPR_TYPEID_INFO:
|
||||
sema_trace_exprid_liveness(expr->typeid_info_expr.parent);
|
||||
return;
|
||||
case EXPR_TRY_UNWRAP:
|
||||
sema_trace_expr_liveness(expr->try_unwrap_expr.optional);
|
||||
if (expr->try_unwrap_expr.assign_existing)
|
||||
{
|
||||
sema_trace_expr_liveness(expr->try_unwrap_expr.lhs);
|
||||
}
|
||||
else
|
||||
{
|
||||
sema_trace_decl_liveness(expr->try_unwrap_expr.decl);
|
||||
}
|
||||
return;
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
sema_trace_expr_list_liveness(expr->try_unwrap_chain_expr);
|
||||
return;
|
||||
case EXPR_TYPEID:
|
||||
return;
|
||||
case EXPR_VARIANT:
|
||||
sema_trace_exprid_liveness(expr->variant_expr.ptr);
|
||||
sema_trace_exprid_liveness(expr->variant_expr.type_id);
|
||||
return;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
void sema_trace_liveness(void)
|
||||
{
|
||||
if (global_context.main)
|
||||
{
|
||||
sema_trace_decl_liveness(global_context.main);
|
||||
}
|
||||
FOREACH_BEGIN(Module *module, global_context.module_list)
|
||||
FOREACH_BEGIN(CompilationUnit *unit, module->units)
|
||||
FOREACH_BEGIN(Decl *function, unit->functions)
|
||||
if (function->is_export || function->no_strip) sema_trace_decl_liveness(function);
|
||||
FOREACH_END();
|
||||
FOREACH_BEGIN(Decl *method, unit->methods)
|
||||
if (method->is_export || method->no_strip) sema_trace_decl_liveness(method);
|
||||
FOREACH_END();
|
||||
FOREACH_BEGIN(Decl *var, unit->vars)
|
||||
if (var->is_export || var->no_strip) sema_trace_decl_liveness(var);
|
||||
FOREACH_END();
|
||||
FOREACH_BEGIN(Decl *xxlizer, unit->xxlizers)
|
||||
sema_trace_decl_liveness(xxlizer);
|
||||
FOREACH_END();
|
||||
FOREACH_END();
|
||||
FOREACH_END();
|
||||
}
|
||||
static void sema_trace_decl_liveness(Decl *decl)
|
||||
{
|
||||
if (!decl || decl->is_live) return;
|
||||
decl->is_live = true;
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_POISONED:
|
||||
case DECL_ATTRIBUTE:
|
||||
case DECL_BITSTRUCT:
|
||||
case DECL_DEFINE:
|
||||
case DECL_DISTINCT:
|
||||
case DECL_ENUM:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_FAULT:
|
||||
case DECL_FAULTVALUE:
|
||||
return;
|
||||
case DECL_CT_CASE:
|
||||
case DECL_CT_ELIF:
|
||||
case DECL_CT_ELSE:
|
||||
case DECL_CT_IF:
|
||||
case DECL_CT_SWITCH:
|
||||
case DECL_CT_ASSERT:
|
||||
case DECL_CT_ECHO:
|
||||
case DECL_GENERIC:
|
||||
case DECL_IMPORT:
|
||||
case DECL_CT_INCLUDE:
|
||||
case DECL_LABEL:
|
||||
case DECL_MACRO:
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_GLOBALS:
|
||||
UNREACHABLE
|
||||
return;
|
||||
case DECL_FUNC:
|
||||
sema_trace_stmt_liveness(astptrzero(decl->func_decl.body));
|
||||
return;
|
||||
case DECL_VAR:
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_UNWRAPPED:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sema_trace_expr_liveness(decl->var.init_expr);
|
||||
return;
|
||||
case DECL_INITIALIZE:
|
||||
case DECL_FINALIZE:
|
||||
sema_trace_stmt_liveness(astptrzero(decl->xxlizer.init));
|
||||
return;
|
||||
case DECL_STRUCT:
|
||||
case DECL_TYPEDEF:
|
||||
case DECL_UNION:
|
||||
return;
|
||||
case DECL_DECLARRAY:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
@@ -317,6 +317,11 @@ RESOLVE_LAMBDA:;
|
||||
FOREACH_END();
|
||||
if (found_lambda) goto RESOLVE_LAMBDA;
|
||||
|
||||
if (active_target.strip_unused && !active_target.testing)
|
||||
{
|
||||
sema_trace_liveness();
|
||||
}
|
||||
|
||||
if (active_target.panicfn || !active_target.no_stdlib)
|
||||
{
|
||||
const char *panicfn = active_target.panicfn ? active_target.panicfn : "std::core::builtin::panic";
|
||||
|
||||
@@ -308,6 +308,7 @@ void symtab_init(uint32_t capacity)
|
||||
attribute_list[ATTRIBUTE_NOINIT] = KW_DEF("@noinit");
|
||||
attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("@noinline");
|
||||
attribute_list[ATTRIBUTE_NORETURN] = KW_DEF("@noreturn");
|
||||
attribute_list[ATTRIBUTE_NOSTRIP] = KW_DEF("@nostrip");
|
||||
attribute_list[ATTRIBUTE_OBFUSCATE] = KW_DEF("@obfuscate");
|
||||
attribute_list[ATTRIBUTE_OPERATOR] = KW_DEF("@operator");
|
||||
attribute_list[ATTRIBUTE_OVERLAP] = KW_DEF("@overlap");
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.68"
|
||||
#define COMPILER_VERSION "0.4.69"
|
||||
@@ -8,16 +8,16 @@ fn void! test_likely() @test
|
||||
|
||||
fn void! test_unlikely() @test
|
||||
{
|
||||
assert(@unlikely(2 < 1));
|
||||
assert(@unlikely(2 < 1, 0.5));
|
||||
assert(!@unlikely(2 < 1));
|
||||
assert(!@unlikely(2 < 1, 0.5));
|
||||
}
|
||||
|
||||
fn void! test_expect() @test
|
||||
{
|
||||
assert(@expect(2 > 1, true));
|
||||
assert(@expect(2 < 1, false));
|
||||
assert(!@expect(2 < 1, false));
|
||||
|
||||
assert(@expect(2 > 1, true, 0.5));
|
||||
assert(@expect(2 < 1, false, 0.5));
|
||||
assert(!@expect(2 < 1, false, 0.5));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user