main.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #define VERSION_STRING "v0.0.3"
  2. #include "common.cpp"
  3. #include "timings.cpp"
  4. #include "unicode.cpp"
  5. #include "tokenizer.cpp"
  6. #include "parser.cpp"
  7. // #include "printer.cpp"
  8. #include "checker/checker.cpp"
  9. #include "ssa.cpp"
  10. #include "ssa_opt.cpp"
  11. #include "ssa_print.cpp"
  12. // #include "vm.cpp"
  13. // NOTE(bill): `name` is used in debugging and profiling modes
  14. i32 win32_exec_command_line_app(char *name, char *fmt, ...) {
  15. STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
  16. PROCESS_INFORMATION pi = {0};
  17. char cmd_line[4096] = {0};
  18. isize cmd_len;
  19. va_list va;
  20. gbTempArenaMemory tmp;
  21. String16 cmd;
  22. i32 exit_code = 0;
  23. start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  24. start_info.wShowWindow = SW_SHOW;
  25. start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  26. start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  27. start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
  28. va_start(va, fmt);
  29. cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
  30. va_end(va);
  31. // gb_printf("%.*s\n", cast(int)cmd_len, cmd_line);
  32. tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
  33. cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
  34. if (CreateProcessW(NULL, cmd.text,
  35. NULL, NULL, true, 0, NULL, NULL,
  36. &start_info, &pi)) {
  37. WaitForSingleObject(pi.hProcess, INFINITE);
  38. GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
  39. CloseHandle(pi.hProcess);
  40. CloseHandle(pi.hThread);
  41. } else {
  42. // NOTE(bill): failed to create process
  43. gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
  44. exit_code = -1;
  45. }
  46. gb_temp_arena_memory_end(tmp);
  47. return exit_code;
  48. }
  49. typedef enum ArchKind {
  50. ArchKind_x64,
  51. ArchKind_x86,
  52. } ArchKind;
  53. typedef struct ArchData {
  54. BaseTypeSizes sizes;
  55. String llc_flags;
  56. String link_flags;
  57. } ArchData;
  58. ArchData make_arch_data(ArchKind kind) {
  59. ArchData data = {0};
  60. switch (kind) {
  61. case ArchKind_x64:
  62. default:
  63. data.sizes.word_size = 8;
  64. data.sizes.max_align = 16;
  65. data.llc_flags = str_lit("-march=x86-64 ");
  66. data.link_flags = str_lit("/machine:x64 ");
  67. break;
  68. case ArchKind_x86:
  69. data.sizes.word_size = 4;
  70. data.sizes.max_align = 8;
  71. data.llc_flags = str_lit("-march=x86 ");
  72. data.link_flags = str_lit("/machine:x86 ");
  73. break;
  74. }
  75. return data;
  76. }
  77. void usage(char *argv0) {
  78. gb_printf_err("%s is a tool for managing Odin source code\n", argv0);
  79. gb_printf_err("Usage:");
  80. gb_printf_err("\n\t%s command [arguments]\n", argv0);
  81. gb_printf_err("Commands:");
  82. gb_printf_err("\n\tbuild compile .odin file");
  83. gb_printf_err("\n\trun compile and run .odin file");
  84. gb_printf_err("\n\tversion print Odin version");
  85. gb_printf_err("\n\n");
  86. }
  87. int main(int argc, char **argv) {
  88. if (argc < 2) {
  89. usage(argv[0]);
  90. return 1;
  91. }
  92. Timings timings = {0};
  93. timings_init(&timings, str_lit("Total Time"), 128);
  94. // defer (timings_destroy(&timings));
  95. #if 1
  96. init_string_buffer_memory();
  97. init_global_error_collector();
  98. String module_dir = get_module_dir();
  99. init_universal_scope();
  100. char *init_filename = NULL;
  101. bool run_output = false;
  102. String arg1 = make_string_c(argv[1]);
  103. if (str_eq(arg1, str_lit("run"))) {
  104. run_output = true;
  105. init_filename = argv[2];
  106. } else if (str_eq(arg1, str_lit("build"))) {
  107. init_filename = argv[2];
  108. } else if (str_eq(arg1, str_lit("version"))) {
  109. gb_printf("%s version %s", argv[0], VERSION_STRING);
  110. return 0;
  111. } else {
  112. usage(argv[0]);
  113. return 1;
  114. }
  115. // TODO(bill): prevent compiling without a linker
  116. timings_start_section(&timings, str_lit("parse files"));
  117. Parser parser = {0};
  118. if (!init_parser(&parser)) {
  119. return 1;
  120. }
  121. // defer (destroy_parser(&parser));
  122. if (parse_files(&parser, init_filename) != ParseFile_None) {
  123. return 1;
  124. }
  125. #if 1
  126. timings_start_section(&timings, str_lit("type check"));
  127. Checker checker = {0};
  128. ArchData arch_data = make_arch_data(ArchKind_x64);
  129. init_checker(&checker, &parser, arch_data.sizes);
  130. // defer (destroy_checker(&checker));
  131. check_parsed_files(&checker);
  132. #endif
  133. #if 1
  134. ssaGen ssa = {0};
  135. if (!ssa_gen_init(&ssa, &checker)) {
  136. return 1;
  137. }
  138. // defer (ssa_gen_destroy(&ssa));
  139. timings_start_section(&timings, str_lit("ssa gen"));
  140. ssa_gen_tree(&ssa);
  141. timings_start_section(&timings, str_lit("ssa opt"));
  142. ssa_opt_tree(&ssa);
  143. timings_start_section(&timings, str_lit("ssa print"));
  144. ssa_print_llvm_ir(&ssa);
  145. // prof_print_all();
  146. #if 1
  147. timings_start_section(&timings, str_lit("llvm-opt"));
  148. char const *output_name = ssa.output_file.filename;
  149. isize base_name_len = gb_path_extension(output_name)-1 - output_name;
  150. String output = make_string(cast(u8 *)output_name, base_name_len);
  151. i32 optimization_level = 0;
  152. optimization_level = gb_clamp(optimization_level, 0, 3);
  153. i32 exit_code = 0;
  154. // For more passes arguments: http://llvm.org/docs/Passes.html
  155. exit_code = win32_exec_command_line_app("llvm-opt",
  156. "%.*sbin/opt %s -o %.*s.bc "
  157. "-mem2reg "
  158. "-memcpyopt "
  159. "-die "
  160. // "-dse "
  161. // "-dce "
  162. // "-S "
  163. "",
  164. LIT(module_dir),
  165. output_name, LIT(output));
  166. if (exit_code != 0) {
  167. return exit_code;
  168. }
  169. #if 1
  170. timings_start_section(&timings, str_lit("llvm-llc"));
  171. // For more arguments: http://llvm.org/docs/CommandGuide/llc.html
  172. exit_code = win32_exec_command_line_app("llvm-llc",
  173. "%.*sbin/llc %.*s.bc -filetype=obj -O%d "
  174. "%.*s "
  175. // "-debug-pass=Arguments "
  176. "",
  177. LIT(module_dir),
  178. LIT(output),
  179. optimization_level,
  180. LIT(arch_data.llc_flags));
  181. if (exit_code != 0) {
  182. return exit_code;
  183. }
  184. timings_start_section(&timings, str_lit("msvc-link"));
  185. gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib");
  186. // defer (gb_string_free(lib_str));
  187. char lib_str_buf[1024] = {0};
  188. for_array(i, parser.foreign_libraries) {
  189. String lib = parser.foreign_libraries.e[i];
  190. isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
  191. " %.*s.lib", LIT(lib));
  192. lib_str = gb_string_appendc(lib_str, lib_str_buf);
  193. }
  194. exit_code = win32_exec_command_line_app("msvc-link",
  195. "link %.*s.obj -OUT:%.*s.exe %s "
  196. "/defaultlib:libcmt "
  197. "/nologo /incremental:no /opt:ref /subsystem:console "
  198. " %.*s "
  199. "",
  200. LIT(output), LIT(output),
  201. lib_str, LIT(arch_data.link_flags));
  202. if (exit_code != 0) {
  203. return exit_code;
  204. }
  205. // timings_print_all(&timings);
  206. if (run_output) {
  207. win32_exec_command_line_app("odin run",
  208. "%.*s.exe", cast(int)base_name_len, output_name);
  209. }
  210. #endif
  211. #endif
  212. #endif
  213. #endif
  214. return 0;
  215. }