From cec9f7abfe55a70fc7e56960eda1870aee596cbb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 19 Nov 2017 15:06:56 +0000 Subject: [PATCH] Add `-debug` command (still in development) --- src/build_settings.cpp | 1 + src/common.cpp | 2 ++ src/gb/gb.h | 24 ++++++++++++++- src/ir.cpp | 57 ++++++++++++++++++------------------ src/ir_print.cpp | 66 ++++++++++++++++++++++-------------------- src/main.cpp | 40 +++++++++++++++---------- src/parser.cpp | 2 +- src/string.cpp | 39 +++++++------------------ 8 files changed, 125 insertions(+), 106 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b18dc0c43..496de46ba 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -22,6 +22,7 @@ struct BuildContext { i32 optimization_level; bool show_timings; bool keep_temp_files; + bool debug; gbAffinity affinity; isize thread_count; diff --git a/src/common.cpp b/src/common.cpp index 22e94ed84..9fee2fb19 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -112,6 +112,8 @@ u128 fnv128a(void const *data, isize len) { return h; } + + #include "map.cpp" #include "ptr_set.cpp" #include "string_set.cpp" diff --git a/src/gb/gb.h b/src/gb/gb.h index dfd701b8d..3e3f147dc 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -1515,6 +1515,7 @@ typedef struct gbStringHeader { #define GB_STRING_HEADER(str) (cast(gbStringHeader *)(str) - 1) +GB_DEF gbString gb_string_make_reserve (gbAllocator a, isize capacity); GB_DEF gbString gb_string_make (gbAllocator a, char const *str); GB_DEF gbString gb_string_make_length (gbAllocator a, void const *str, isize num_bytes); GB_DEF void gb_string_free (gbString str); @@ -6504,6 +6505,27 @@ gb_inline void gb__set_string_length (gbString str, isize len) { GB_STRING_HEAD gb_inline void gb__set_string_capacity(gbString str, isize cap) { GB_STRING_HEADER(str)->capacity = cap; } +gbString gb_string_make_reserve(gbAllocator a, isize capacity) { + isize header_size = gb_size_of(gbStringHeader); + void *ptr = gb_alloc(a, header_size + capacity + 1); + + gbString str; + gbStringHeader *header; + + if (ptr == NULL) return NULL; + gb_zero_size(ptr, header_size + capacity + 1); + + str = cast(char *)ptr + header_size; + header = GB_STRING_HEADER(str); + header->allocator = a; + header->length = 0; + header->capacity = capacity; + str[capacity] = '\0'; + + return str; +} + + gb_inline gbString gb_string_make(gbAllocator a, char const *str) { isize len = str ? gb_strlen(str) : 0; return gb_string_make_length(a, str, len); @@ -6516,8 +6538,8 @@ gbString gb_string_make_length(gbAllocator a, void const *init_str, isize num_by gbString str; gbStringHeader *header; - if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1); if (ptr == NULL) return NULL; + if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1); str = cast(char *)ptr + header_size; header = GB_STRING_HEADER(str); diff --git a/src/ir.cpp b/src/ir.cpp index 175a95db2..aa4bd86b0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -109,6 +109,16 @@ struct irBranchBlocks { }; +struct irDebugLocation { + TokenPos pos; + irDebugInfo *debug_scope; +}; + +struct irDebugScope { + irDebugScope * parent; + irDebugLocation loc; +}; + struct irProcedure { irProcedure * parent; Array children; @@ -125,6 +135,8 @@ struct irProcedure { bool is_export; bool is_entry_point; + irDebugInfo * debug_scope; + irValue * return_ptr; Array params; Array defer_stmts; @@ -146,6 +158,9 @@ struct irProcedure { i32 block_count; }; + + + #define IR_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" #define IR_TYPE_INFO_DATA_NAME "__$type_info_data" #define IR_TYPE_INFO_TYPES_NAME "__$type_info_types_data" @@ -231,11 +246,10 @@ struct irProcedure { irValue **args; \ isize arg_count; \ irValue * context_ptr; \ - irDebugInfo *debug_location; \ }) \ IR_INSTR_KIND(StartupRuntime, i32) \ IR_INSTR_KIND(DebugDeclare, struct { \ - irDebugInfo *debug_info; \ + irDebugInfo *scope; \ AstNode * expr; \ Entity * entity; \ bool is_addr; \ @@ -388,10 +402,12 @@ struct irValueParam { Array referrers; }; + struct irValue { - irValueKind kind; - i32 index; - bool index_set; + irValueKind kind; + i32 index; + bool index_set; + irDebugLocation loc; union { irValueConstant Constant; irValueConstantSlice ConstantSlice; @@ -490,8 +506,6 @@ enum irDebugInfoKind { irDebugInfo_Proc, irDebugInfo_AllProcs, - irDebugInfo_Location, - irDebugInfo_BasicType, // basic types irDebugInfo_ProcType, irDebugInfo_DerivedType, // pointer, typedef @@ -534,11 +548,6 @@ struct irDebugInfo { struct { Array procs; } AllProcs; - struct { - irDebugInfo *scope; - TokenPos pos; - } Location; - struct { String name; @@ -1070,18 +1079,6 @@ irValue *ir_instr_call(irProcedure *p, irValue *value, irValue *return_ptr, irVa v->Instr.Call.arg_count = arg_count; v->Instr.Call.type = result_type; v->Instr.Call.context_ptr = context_ptr; - - irDebugInfo **pp = map_get(&p->module->debug_info, hash_entity(p->entity)); - if (pp != nullptr) { - GB_ASSERT_MSG(pp != nullptr, "%.*s %p", LIT(p->name), p->entity); - irDebugInfo *dl = ir_alloc_debug_info(p->module->allocator, irDebugInfo_Location); - dl->Location.scope = *pp; - dl->Location.pos = p->entity->token.pos; - map_set(&p->module->debug_info, hash_pointer(v), dl); - - v->Instr.Call.debug_location = dl; - } - return v; } @@ -1100,9 +1097,9 @@ irValue *ir_instr_comment(irProcedure *p, String text) { return v; } -irValue *ir_instr_debug_declare(irProcedure *p, irDebugInfo *debug_info, AstNode *expr, Entity *entity, bool is_addr, irValue *value) { +irValue *ir_instr_debug_declare(irProcedure *p, irDebugInfo *scope, AstNode *expr, Entity *entity, bool is_addr, irValue *value) { irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare); - v->Instr.DebugDeclare.debug_info = debug_info; + v->Instr.DebugDeclare.scope = scope; v->Instr.DebugDeclare.expr = expr; v->Instr.DebugDeclare.entity = entity; v->Instr.DebugDeclare.is_addr = is_addr; @@ -1130,7 +1127,6 @@ irValue *ir_value_constant_slice(gbAllocator a, Type *type, irValue *backing_arr } - irValue *ir_emit(irProcedure *proc, irValue *instr) { GB_ASSERT(instr->kind == irValue_Instr); irBlock *b = proc->curr_block; @@ -1519,6 +1515,8 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na di->Proc.file = file; di->Proc.pos = entity->token.pos; + proc->debug_scope = di; + map_set(&proc->module->debug_info, hash_entity(entity), di); return di; } @@ -7665,7 +7663,10 @@ void ir_init_module(irModule *m, Checker *c) { m->tmp_allocator = gb_arena_allocator(&m->tmp_arena); m->info = &c->info; - m->generate_debug_info = build_context.ODIN_OS == "windows" && build_context.word_size == 8; + m->generate_debug_info = false; + if (build_context.debug) { + m->generate_debug_info = build_context.ODIN_OS == "windows" && build_context.word_size == 8; + } map_init(&m->values, heap_allocator()); map_init(&m->members, heap_allocator()); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index f32e0d354..487a0bf5f 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1465,8 +1465,19 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { } ir_write_string(f, ")"); - if (m->generate_debug_info && call->debug_location) { - ir_fprintf(f, ", !dbg !%d", call->debug_location->id); + if (m->generate_debug_info) { + TokenPos pos = value->loc.pos; + irDebugInfo *scope = value->loc.debug_scope; + i32 id = 0; + irProcedure *proc = instr->parent->parent; + if (scope != nullptr) { + id = scope->id; + } else if (proc->debug_scope != nullptr) { + id = proc->debug_scope->id; + } + if (id > 0) { + ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, id); + } } ir_write_string(f, "\n"); @@ -1632,17 +1643,17 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { #endif case irInstr_DebugDeclare: { + if (!m->generate_debug_info) { + break; + } + irInstrDebugDeclare *dd = &instr->DebugDeclare; Type *vt = ir_type(dd->value); - irDebugInfo *di = dd->debug_info; + irDebugInfo *di = dd->scope; Entity *e = dd->entity; String name = e->token.string; TokenPos pos = e->token.pos; - - if (!m->generate_debug_info) { - ir_write_string(f, "; "); - } ir_write_string(f, "call void @llvm.dbg.declare("); ir_write_string(f, "metadata "); ir_print_type(f, m, vt); @@ -1762,14 +1773,12 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { break; } - if (proc->entity != nullptr) { - if (proc->body != nullptr) { - irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity)); - if (di_ != nullptr) { - irDebugInfo *di = *di_; - GB_ASSERT(di->kind == irDebugInfo_Proc); - ir_fprintf(f, "!dbg !%d ", di->id); - } + if (m->generate_debug_info && proc->entity != nullptr && proc->body != nullptr) { + irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity)); + if (di_ != nullptr) { + irDebugInfo *di = *di_; + GB_ASSERT(di->kind == irDebugInfo_Proc); + ir_fprintf(f, "!dbg !%d ", di->id); } } @@ -1846,14 +1855,15 @@ void print_llvm_ir(irGen *ir) { irModule *m = &ir->module; irFileBuffer buf = {}, *f = &buf; ir_file_buffer_init(f, &ir->output_file); + defer (ir_file_buffer_destroy(f)); if (m->generate_debug_info) { - ir_write_string(f, "target datalayout = \"e-m:w-i64:64-f80:128-n8:16:32:64-S128\"\n"); - ir_write_string(f, "target triple = \"x86_64-pc-windows-msvc19.11.25508\"\n\n"); + i32 word_bits = cast(i32)(8*build_context.word_size); + ir_fprintf(f, "target datalayout = \"e-m:w-i%d:%d-f80:128-n8:16:32:64-S128\"\n", word_bits, word_bits); + ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc17\"\n\n", word_bits == 64 ? "-64" : ""); + ir_fprintf(f, "\n\n"); } - - ir_print_encoded_local(f, str_lit("..opaque")); ir_write_string(f, str_lit(" = type {};\n")); ir_print_encoded_local(f, str_lit("..string")); @@ -1870,7 +1880,6 @@ void print_llvm_ir(irGen *ir) { ir_print_encoded_local(f, str_lit("..complex128")); ir_write_string(f, str_lit(" = type {double, double} ; Basic_complex128\n")); - ir_print_encoded_local(f, str_lit("..any")); ir_write_string(f, str_lit(" = type {")); ir_print_type(f, m, t_rawptr); @@ -2016,16 +2025,17 @@ void print_llvm_ir(irGen *ir) { ", runtimeVersion: 0" ", isOptimized: false" ", emissionKind: FullDebug" + ", retainedTypes: !0" + ", enums: !0" + ", globals: !0" ")", file->id, LIT(build_context.ODIN_VERSION)); break; } case irDebugInfo_File: - ir_fprintf(f, "!DIFile(filename: \""); - ir_print_escape_path(f, di->File.filename); - ir_fprintf(f, "\", directory: \""); - ir_print_escape_path(f, di->File.directory); + ir_fprintf(f, "!DIFile(filename: \""); ir_print_escape_path(f, di->File.filename); + ir_fprintf(f, "\", directory: \""); ir_print_escape_path(f, di->File.directory); ir_fprintf(f, "\""); ir_fprintf(f, ")"); break; @@ -2057,12 +2067,6 @@ void print_llvm_ir(irGen *ir) { ir_write_byte(f, '}'); break; - case irDebugInfo_Location: - GB_ASSERT(di->Location.scope != nullptr); - ir_fprintf(f, "!DILocation(line: %td, column: %td, scope: !%d)", - di->Location.pos.line, di->Location.pos.column, di->Location.scope->id); - break; - default: GB_PANIC("Unhandled irDebugInfo kind %d", di->kind); break; @@ -2077,6 +2081,4 @@ void print_llvm_ir(irGen *ir) { ir_fprintf(f, "!%d = !{i32 2, !\"CodeView\", i32 1}\n", di_code_view); ir_fprintf(f, "!%d = !{i32 1, !\"wchar_size\", i32 2}\n", di_wchar_size); } - - ir_file_buffer_destroy(f); } diff --git a/src/main.cpp b/src/main.cpp index 1f943b7a3..32cc5fbff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -209,6 +209,7 @@ enum BuildFlagKind { BuildFlag_KeepTempFiles, BuildFlag_Collection, BuildFlag_BuildMode, + BuildFlag_Debug, BuildFlag_COUNT, }; @@ -244,6 +245,7 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String); + add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None); Array flag_args = args; @@ -483,6 +485,10 @@ bool parse_build_flags(Array args) { break; } + + case BuildFlag_Debug: + build_context.debug = true; + break; } } @@ -778,19 +784,24 @@ int main(int arg_count, char **arg_ptr) { } char *output_ext = "exe"; - char *link_settings = ""; + gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); + defer (gb_string_free(link_settings)); + if (build_context.is_dll) { output_ext = "dll"; - link_settings = "/DLL"; + link_settings = gb_string_append_fmt(link_settings, "/DLL"); } else { - link_settings = "/ENTRY:mainCRTStartup"; + link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup"); + } + + if (build_context.debug) { + link_settings = gb_string_append_fmt(link_settings, " /DEBUG /SYMBOLS"); } exit_code = system_exec_command_line_app("msvc-link", true, "link \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " "/defaultlib:libcmt " // "/nodefaultlib " - // "/debug " "/nologo /incremental:no /opt:ref /subsystem:CONSOLE " " %.*s " " %s " @@ -840,9 +851,8 @@ int main(int arg_count, char **arg_ptr) { // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library // files can be passed with -l: gbString lib_str = gb_string_make(heap_allocator(), "-L/"); - defer (gb_string_free(lib_str)); - char lib_str_buf[1024] = {0}; + for_array(i, ir_gen.module.foreign_library_paths) { String lib = ir_gen.module.foreign_library_paths[i]; @@ -850,19 +860,18 @@ int main(int arg_count, char **arg_ptr) { // This allows you to specify '-f' in a #foreign_system_library, // without having to implement any new syntax specifically for MacOS. #if defined(GB_SYSTEM_OSX) - isize len; - if(lib.len > 2 && lib[0] == '-' && lib[1] == 'f') { + if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') { // framework thingie - len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2); + lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2); } else if (string_has_extension(lib, str_lit("a"))) { // static libs, absolute full path relative to the file in which the lib was imported from - len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " %.*s ", LIT(lib)); + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); } else if (string_has_extension(lib, str_lit("dylib"))) { // dynamic lib, relative path to executable - len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib)); + lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths - len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l%.*s ", LIT(lib)); + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); } #else // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, @@ -872,18 +881,17 @@ int main(int arg_count, char **arg_ptr) { // the system library paths for the library file). if (string_has_extension(lib, str_lit("a"))) { // static libs, absolute full path relative to the file in which the lib was imported from - isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%.*s ", LIT(lib)); + lib_str = gb_string_append_fmt(lib_str, " -l:%.*s ", LIT(lib)); } else if (string_has_extension(lib, str_lit("so"))) { // dynamic lib, relative path to executable // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible // at runtimeto the executable - isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib)); + lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths - isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l%.*s ", LIT(lib)); + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); } #endif - lib_str = gb_string_appendc(lib_str, lib_str_buf); } // Unlike the Win32 linker code, the output_ext includes the dot, because diff --git a/src/parser.cpp b/src/parser.cpp index c2c781392..d39267869 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4679,7 +4679,7 @@ Array parse_stmt_list(AstFile *f) { ParseFileError init_ast_file(AstFile *f, String fullpath, TokenPos *err_pos) { f->fullpath = string_trim_whitespace(fullpath); // Just in case - if (!string_has_extension(f->fullpath, str_lit("odin"))) { + if (!string_ends_with(f->fullpath, str_lit(".odin"))) { return ParseFile_WrongExtension; } TokenizerInitError err = init_tokenizer(&f->tokenizer, f->fullpath); diff --git a/src/string.cpp b/src/string.cpp index 8e6006c46..822a386d7 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -180,17 +180,20 @@ template bool operator >= (String const &a, char const (&b)[N]) { retu -gb_inline bool str_has_prefix(String s, String prefix) { - isize i; - if (prefix.len < s.len) { +gb_inline bool string_starts_with(String s, String prefix) { + if (prefix.len > s.len) { return false; } - for (i = 0; i < prefix.len; i++) { - if (s[i] != prefix[i]) { - return false; - } + + return substring(s, 0, prefix.len) == prefix; +} + +gb_inline bool string_ends_with(String s, String suffix) { + if (suffix.len > s.len) { + return false; } - return true; + + return substring(s, s.len-suffix.len, s.len) == suffix; } gb_inline isize string_extension_position(String str) { @@ -225,26 +228,6 @@ String string_trim_whitespace(String str) { return str; } -gb_inline bool string_has_extension(String str, String ext) { - str = string_trim_whitespace(str); - if (str.len <= ext.len+1) { - return false; - } - isize len = str.len; - for (isize i = len-1; i >= 0; i--) { - if (str[i] == '.') { - break; - } - len--; - } - if (len == 0) { - return false; - } - - u8 *s = str.text + len; - return gb_memcompare(s, ext.text, ext.len) == 0; -} - bool string_contains_char(String s, u8 c) { isize i; for (i = 0; i < s.len; i++) {