diff options
Diffstat (limited to 'src/main.c')
| -rw-r--r-- | src/main.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 000000000..cf5d2379b --- /dev/null +++ b/src/main.c @@ -0,0 +1,272 @@ +#if defined(__cplusplus) +extern "C" { +#endif +#define VERSION_STRING "v0.0.3c" + +#include "common.c" +#include "timings.c" +#include "unicode.c" +#include "tokenizer.c" +#include "parser.c" +// #include "printer.c" +#include "checker/checker.c" +#include "ssa.c" +#include "ssa_opt.c" +#include "ssa_print.c" +// #include "vm.c" + +// NOTE(bill): `name` is used in debugging and profiling modes +i32 win32_exec_command_line_app(char *name, char *fmt, ...) { + STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)}; + PROCESS_INFORMATION pi = {0}; + char cmd_line[4096] = {0}; + isize cmd_len; + va_list va; + gbTempArenaMemory tmp; + String16 cmd; + i32 exit_code = 0; + + start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + start_info.wShowWindow = SW_SHOW; + start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + + va_start(va, fmt); + cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va); + va_end(va); + // gb_printf("%.*s\n", cast(int)cmd_len, cmd_line); + + tmp = gb_temp_arena_memory_begin(&string_buffer_arena); + + cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1)); + + if (CreateProcessW(NULL, cmd.text, + NULL, NULL, true, 0, NULL, NULL, + &start_info, &pi)) { + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } else { + // NOTE(bill): failed to create process + gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line); + exit_code = -1; + } + + gb_temp_arena_memory_end(tmp); + return exit_code; +} + +typedef enum ArchKind { + ArchKind_x64, + ArchKind_x86, +} ArchKind; + +typedef struct ArchData { + BaseTypeSizes sizes; + String llc_flags; + String link_flags; +} ArchData; + +ArchData make_arch_data(ArchKind kind) { + ArchData data = {0}; + + switch (kind) { + case ArchKind_x64: + default: + data.sizes.word_size = 8; + data.sizes.max_align = 16; + data.llc_flags = str_lit("-march=x86-64 "); + data.link_flags = str_lit("/machine:x64 "); + break; + + case ArchKind_x86: + data.sizes.word_size = 4; + data.sizes.max_align = 8; + data.llc_flags = str_lit("-march=x86 "); + data.link_flags = str_lit("/machine:x86 "); + break; + } + + return data; +} + +void usage(char *argv0) { + gb_printf_err("%s is a tool for managing Odin source code\n", argv0); + gb_printf_err("Usage:"); + gb_printf_err("\n\t%s command [arguments]\n", argv0); + gb_printf_err("Commands:"); + gb_printf_err("\n\tbuild compile .odin file"); + gb_printf_err("\n\trun compile and run .odin file"); + gb_printf_err("\n\tversion print Odin version"); + gb_printf_err("\n\n"); +} + +int main(int argc, char **argv) { + if (argc < 2) { + usage(argv[0]); + return 1; + } + + Timings timings = {0}; + timings_init(&timings, str_lit("Total Time"), 128); + // defer (timings_destroy(&timings)); + +#if 1 + init_string_buffer_memory(); + init_global_error_collector(); + + String module_dir = get_module_dir(); + + init_universal_scope(); + + char *init_filename = NULL; + bool run_output = false; + String arg1 = make_string_c(argv[1]); + if (str_eq(arg1, str_lit("run"))) { + run_output = true; + init_filename = argv[2]; + } else if (str_eq(arg1, str_lit("build"))) { + init_filename = argv[2]; + } else if (str_eq(arg1, str_lit("version"))) { + gb_printf("%s version %s", argv[0], VERSION_STRING); + return 0; + } else { + usage(argv[0]); + return 1; + } + + // TODO(bill): prevent compiling without a linker + + timings_start_section(&timings, str_lit("parse files")); + + Parser parser = {0}; + if (!init_parser(&parser)) { + return 1; + } + // defer (destroy_parser(&parser)); + + if (parse_files(&parser, init_filename) != ParseFile_None) { + return 1; + } + + +#if 1 + timings_start_section(&timings, str_lit("type check")); + + Checker checker = {0}; + ArchData arch_data = make_arch_data(ArchKind_x64); + + init_checker(&checker, &parser, arch_data.sizes); + // defer (destroy_checker(&checker)); + + check_parsed_files(&checker); + + +#endif +#if 1 + + ssaGen ssa = {0}; + if (!ssa_gen_init(&ssa, &checker)) { + return 1; + } + // defer (ssa_gen_destroy(&ssa)); + + timings_start_section(&timings, str_lit("ssa gen")); + ssa_gen_tree(&ssa); + + timings_start_section(&timings, str_lit("ssa opt")); + ssa_opt_tree(&ssa); + + timings_start_section(&timings, str_lit("ssa print")); + ssa_print_llvm_ir(&ssa); + + // prof_print_all(); + +#if 1 + timings_start_section(&timings, str_lit("llvm-opt")); + + char const *output_name = ssa.output_file.filename; + isize base_name_len = gb_path_extension(output_name)-1 - output_name; + String output = make_string(cast(u8 *)output_name, base_name_len); + + i32 optimization_level = 0; + optimization_level = gb_clamp(optimization_level, 0, 3); + + i32 exit_code = 0; + // For more passes arguments: http://llvm.org/docs/Passes.html + exit_code = win32_exec_command_line_app("llvm-opt", + "%.*sbin/opt %s -o %.*s.bc " + "-mem2reg " + "-memcpyopt " + "-die " + // "-dse " + // "-dce " + // "-S " + "", + LIT(module_dir), + output_name, LIT(output)); + if (exit_code != 0) { + return exit_code; + } + + #if 1 + timings_start_section(&timings, str_lit("llvm-llc")); + // For more arguments: http://llvm.org/docs/CommandGuide/llc.html + exit_code = win32_exec_command_line_app("llvm-llc", + "%.*sbin/llc %.*s.bc -filetype=obj -O%d " + "%.*s " + // "-debug-pass=Arguments " + "", + LIT(module_dir), + LIT(output), + optimization_level, + LIT(arch_data.llc_flags)); + if (exit_code != 0) { + return exit_code; + } + + timings_start_section(&timings, str_lit("msvc-link")); + + gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib"); + // defer (gb_string_free(lib_str)); + char lib_str_buf[1024] = {0}; + for_array(i, parser.foreign_libraries) { + String lib = parser.foreign_libraries.e[i]; + isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), + " %.*s.lib", LIT(lib)); + lib_str = gb_string_appendc(lib_str, lib_str_buf); + } + + exit_code = win32_exec_command_line_app("msvc-link", + "link %.*s.obj -OUT:%.*s.exe %s " + "/defaultlib:libcmt " + "/nologo /incremental:no /opt:ref /subsystem:console " + " %.*s " + "", + LIT(output), LIT(output), + lib_str, LIT(arch_data.link_flags)); + if (exit_code != 0) { + return exit_code; + } + + // timings_print_all(&timings); + + if (run_output) { + win32_exec_command_line_app("odin run", + "%.*s.exe", cast(int)base_name_len, output_name); + } + #endif +#endif +#endif +#endif + + + return 0; +} + +#if defined(__cplusplus) +} +#endif |