Add --strip-unused.

This commit is contained in:
Christoffer Lerno
2023-02-16 22:02:44 +01:00
committed by Christoffer Lerno
parent 0aa776d61b
commit a0a5c940f1
40 changed files with 681 additions and 94 deletions

View File

@@ -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)

View File

@@ -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.");
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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;
/*

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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,

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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:

View File

@@ -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);

View 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(&current);
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
}
}

View File

@@ -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";

View File

@@ -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");

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.68"
#define COMPILER_VERSION "0.4.69"

View File

@@ -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));
}