diff --git a/bootstrap/build.c b/bootstrap/build.c index 22474cb..6a9e6f0 100644 --- a/bootstrap/build.c +++ b/bootstrap/build.c @@ -145,6 +145,8 @@ fn void compile_c(const CompileOptions *const options, char** envp) memcpy(vb_add(args, array_length(static_options)), static_options, sizeof(static_options)); } + *vb_add(args, 1) = "-DSILENT"; + if (options->compiler == clang) { *vb_add(args, 1) = "-MJ"; @@ -364,14 +366,13 @@ fn void run_tests(Arena* arena, TestOptions const * const test_options, char** e } } -int main(int argc, char* argv[], char** envp) +fn void entry_point(int argc, char* argv[], char* envp[]) { if (argc < 2) { print("Expected some arguments\n"); - return 1; + fail(); } - // calibrate_cpu_timer(); CompilerBackend preferred_compiler_backend = COMPILER_BACKEND_COUNT; Command command = COMMAND_COUNT; @@ -437,7 +438,7 @@ int main(int argc, char* argv[], char** envp) if (command == COMMAND_COUNT && !source_file_path.pointer) { print("Expected a command\n"); - return 1; + fail(); } if (command == COMMAND_COUNT) @@ -461,12 +462,8 @@ int main(int argc, char* argv[], char** envp) fail(); } - Linkage linkage = -#if defined(__linux__) - LINKAGE_STATIC; -#else - LINKAGE_DYNAMIC; -#endif + // Test always with dynamic linkage because it's more trustworthy + Linkage linkage = LINKAGE_DYNAMIC; compile_and_run(&(CompileOptions) { .in_path = compiler_source_path, @@ -481,8 +478,13 @@ int main(int argc, char* argv[], char** envp) case COMMAND_RUN_TESTS: { Arena* arena = arena_init_default(KB(64)); - Linkage all_linkages[] = { LINKAGE_DYNAMIC, LINKAGE_STATIC }; - static_assert(array_length(all_linkages) == LINKAGE_COUNT); + Linkage all_linkages[] = { + LINKAGE_DYNAMIC, +#ifdef __linux__ + LINKAGE_STATIC +#endif + }; + OptimizationMode all_optimization_modes[] = { O0, O1, diff --git a/bootstrap/lib.h b/bootstrap/lib.h index fc65ab4..2ddd879 100644 --- a/bootstrap/lib.h +++ b/bootstrap/lib.h @@ -97,15 +97,34 @@ FOR_N(_i, 0, ((set)->arr.capacity + 63) / 64) FOR_BIT(it, _i*64, (set)->arr.poin b = temp;\ } while (0) -fn u64 timestamp() +fn +#if LINK_LIBC +struct timespec +#else +u64 +#endif +timestamp() { +#if LINK_LIBC + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts; +#else #if defined(__x86_64__) return __rdtsc(); #else return 0; #endif +#endif } +#if LINK_LIBC +global struct timespec cpu_resolution; +#else +global u64 cpu_frequency; +#endif + + may_be_unused fn void print(const char* format, ...); may_be_unused fn u16 cast_u32_to_u16(u32 source, const char* name, int line) @@ -435,6 +454,75 @@ may_be_unused fn s32 cast_s64_to_s32(s64 source, const char* name, int line) const global u64 page_size = KB(4); #endif +typedef enum TimeUnit +{ + TIME_UNIT_NANOSECONDS, + TIME_UNIT_MICROSECONDS, + TIME_UNIT_MILLISECONDS, + TIME_UNIT_SECONDS, +} TimeUnit; + +fn f64 resolve_timestamp( +#if LINK_LIBC + struct timespec start, struct timespec end, +#else + u64 start, u64 end, +#endif + TimeUnit time_unit) +{ +#if LINK_LIBC + assert(end.tv_sec >= start.tv_sec); + struct timespec result = { + .tv_sec = end.tv_sec - start.tv_sec, + .tv_nsec = end.tv_nsec - start.tv_nsec, + }; + + auto ns_in_a_sec = 1000000000; + if (result.tv_nsec < 0) + { + result.tv_sec -= 1; + result.tv_nsec += ns_in_a_sec; + } + + auto ns = result.tv_sec * ns_in_a_sec + result.tv_nsec; + switch (time_unit) + { + case TIME_UNIT_NANOSECONDS: + return (f64)ns; + case TIME_UNIT_MICROSECONDS: + return ns / 1000.0; + case TIME_UNIT_MILLISECONDS: + return ns / 1000000.0; + case TIME_UNIT_SECONDS: + return ns / 1000000000.0; + } +#else + assert(end >= start); + auto ticks = end - start; + f64 s = (f64)(end - start); + if (cpu_frequency) + { + s = s / (f64)cpu_frequency; + + switch (time_unit) + { + case TIME_UNIT_NANOSECONDS: + return s / 1000000000.0; + case TIME_UNIT_MICROSECONDS: + return s / 1000000.0; + case TIME_UNIT_MILLISECONDS: + return s / 1000.0; + case TIME_UNIT_SECONDS: + return s; + } + } + else + { + // warning: rdtsc frequency not queried (returning ticks as are) + return s; + } +#endif +} const may_be_unused global u8 brace_open = '{'; const may_be_unused global u8 brace_close = '}'; @@ -1425,10 +1513,11 @@ may_be_unused fn u64 os_timer_get() return result; } -global u64 cpu_frequency; - may_be_unused fn void calibrate_cpu_timer() { +#if LINK_LIBC + // clock_getres(CLOCK_MONOTONIC, &cpu_resolution); +#else u64 miliseconds_to_wait = 100; u64 cpu_start = timestamp(); u64 os_frequency = os_timer_freq(); @@ -1445,6 +1534,7 @@ may_be_unused fn void calibrate_cpu_timer() u64 cpu_end = timestamp(); u64 cpu_elapsed = cpu_end - cpu_start; cpu_frequency = os_frequency * cpu_elapsed / os_elapsed; +#endif } fn u8* reserve(u64 size) @@ -1538,7 +1628,6 @@ fn u32 format_decimal(String buffer, u64 decimal) } } -#define SILENT (0) STRUCT(SmallIntResult) { u64 mantissa; @@ -2210,7 +2299,7 @@ fn void write_float_decimal(String buffer, u64* value, u64 count) may_be_unused fn void print(const char* format, ...) { -#if SILENT == 0 +#ifndef SILENT u8 stack_buffer[4096]; va_list args; va_start(args, format); @@ -2463,7 +2552,24 @@ may_be_unused fn void print(const char* format, ...) } else { - __builtin_trap(); + auto dp_uoffset = (u64)dp_offset; + if (dp_uoffset >= olength) + { + write_float_decimal(s_get_slice(u8, buffer, buffer_i, buffer.length), &output, olength); + buffer_i += olength; + auto length = dp_uoffset - olength; + auto memset_slice = s_get_slice(u8, buffer, buffer_i, buffer_i + length); + memset(memset_slice.pointer, 0, length); + buffer_i += length; + } + else + { + write_float_decimal(s_get_slice(u8, buffer, buffer_i + dp_uoffset + 1, buffer.length), &output, olength - dp_uoffset); + buffer.pointer[buffer_i + dp_uoffset] = '.'; + auto dp_index = buffer_i + dp_uoffset + 1; + write_float_decimal(s_get_slice(u8, buffer, buffer_i, buffer.length), &output, dp_uoffset); + buffer_i += olength + 1; + } } } break; } @@ -2692,7 +2798,7 @@ fn void run_command(CStringSlice arguments, char* envp[]) trap(); } - u64 start_ns = timestamp(); + auto start_timestamp = timestamp(); if (pid == 0) { @@ -2712,7 +2818,7 @@ fn void run_command(CStringSlice arguments, char* envp[]) int status = 0; int options = 0; pid_t result = syscall_waitpid(pid, &status, options); - u64 end_ns = timestamp(); + auto end_timestamp = timestamp(); int success = 0; if (result == pid) { @@ -2736,14 +2842,15 @@ fn void run_command(CStringSlice arguments, char* envp[]) fail(); } - if (cpu_frequency) - { - auto ticks = end_ns - start_ns; - auto ticks_f = (f64)ticks; - auto time_frequency_f = (f64)cpu_frequency; - auto s = ticks_f / time_frequency_f; - print("Command run successfully in {f64} s\n", s); - } + auto ms = resolve_timestamp(start_timestamp, end_timestamp, TIME_UNIT_MILLISECONDS); + auto ticks = +#if LINK_LIBC + 0 +#else + cpu_frequency != 0 +#endif + ; + print("Command run successfully in {f64} {cstr}\n", ms, ticks ? "ticks" : "ms"); } } @@ -2840,3 +2947,36 @@ may_be_unused fn Hash32 hash64_fib_end(Hash64 hash) auto result = truncate(Hash32, (hash * 11400714819323198485ull) >> 32); return result; } + +fn void entry_point(int argc, char* argv[], char* envp[]); + +#if LINK_LIBC +int main(int argc, char* argv[], char* envp[]) +{ + entry_point(argc, argv, envp); + return 0; +} +#else +[[gnu::naked]] [[noreturn]] void _start() +{ + __asm__ __volatile__( + "\nxor %ebp, %ebp" + "\npopq %rdi" + "\nmov %rsp, %rsi" + "\nand $~0xf, %rsp" + "\npushq %rsp" + "\npushq $0" + "\ncallq static_entry_point" + "\nud2\n" + ); +} + +void static_entry_point(int argc, char* argv[]) +{ + char** envp = (char**)&argv[argc + 1]; + calibrate_cpu_timer(); + entry_point(argc, argv, envp); + syscall_exit(0); +} + +#endif diff --git a/bootstrap/main.c b/bootstrap/main.c index ff5202a..ee04012 100644 --- a/bootstrap/main.c +++ b/bootstrap/main.c @@ -61,7 +61,7 @@ fn String file_read(Arena* arena, String path) fn void print_string(String message) { -#if SILENT == 0 +#ifndef SILENT ssize_t result = syscall_write(1, message.pointer, message.length); assert(result >= 0); assert((u64)result == message.length); @@ -12538,21 +12538,6 @@ fn void print_ir(Thread* restrict thread) } } -#if LINK_LIBC == 0 -[[gnu::naked]] [[noreturn]] void _start() -{ - __asm__ __volatile__( - "\nxor %ebp, %ebp" - "\npopq %rdi" - "\nmov %rsp, %rsi" - "\nand $~0xf, %rsp" - "\npushq %rsp" - "\npushq $0" - "\ncallq entry_point" - "\nud2\n" - ); -} -#endif fn void dwarf_playground(Thread* thread) { @@ -12817,22 +12802,12 @@ fn void dwarf_playground(Thread* thread) assert(*debug_info_bytes.pointer == 0); } -#if LINK_LIBC -int main(int argc, const char* argv[], char* envp[]) +fn void entry_point(int argc, char* argv[], char* envp[]) { -#else -void entry_point(int argc, const char* argv[]) -{ - char** envp = (char**)&argv[argc + 1]; - unused(envp); -#endif #if DO_UNIT_TESTS unit_tests(); #endif - // calibrate_cpu_timer(); - - Arena* global_arena = arena_init(MB(2), KB(64), KB(64)); { @@ -12890,13 +12865,10 @@ void entry_point(int argc, const char* argv[]) else { code_generation(thread, (CodegenOptions) { - .test_name = test_name, - .backend = compiler_backend, - }, envp); + .test_name = test_name, + .backend = compiler_backend, + }, envp); } thread_clear(thread); -#if LINK_LIBC == 0 - syscall_exit(0); -#endif }