From e4cb28dbf2d0bc70581502d751ba9e4f7a46ed93 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 16 Dec 2015 17:11:35 -0700 Subject: [PATCH] structs have debug information --- src/analyze.cpp | 102 +++++++++++++++++++++++++++++++++-------------- src/analyze.hpp | 1 + src/codegen.cpp | 3 +- src/zig_llvm.cpp | 54 +++++++++++++++++++++++++ src/zig_llvm.hpp | 15 +++++++ 5 files changed, 142 insertions(+), 33 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index b0e12925b4..62e4e5d606 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -114,6 +114,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool buf_appendf(&entry->name, "&%s%s", is_const ? "const " : "", buf_ptr(&child_type->name)); entry->size_in_bits = g->pointer_size_bytes * 8; entry->align_in_bits = g->pointer_size_bytes * 8; + assert(child_type->di_type); entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type, entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name)); entry->data.pointer.child_type = child_type; @@ -269,6 +270,70 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_ } } +static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type) { + assert(struct_type->id == TypeTableEntryIdStruct); + + AstNode *decl_node = struct_type->data.structure.decl_node; + + assert(struct_type->di_type); + assert(!struct_type->data.structure.fields); + + int field_count = decl_node->data.struct_decl.fields.length; + struct_type->data.structure.field_count = field_count; + struct_type->data.structure.fields = allocate(field_count); + + LLVMTypeRef *element_types = allocate(field_count); + LLVMZigDIType **di_element_types = allocate(field_count); + + uint64_t total_size_in_bits = 0; + uint64_t first_field_align_in_bits = 0; + uint64_t offset_in_bits = 0; + + for (int i = 0; i < field_count; i += 1) { + AstNode *field_node = decl_node->data.struct_decl.fields.at(i); + TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; + type_struct_field->name = &field_node->data.struct_field.name; + type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type); + + if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) { + resolve_struct_type(g, import, type_struct_field->type_entry); + } + + di_element_types[i] = LLVMZigCreateDebugMemberType(g->dbuilder, + LLVMZigTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name), + import->di_file, field_node->line + 1, + type_struct_field->type_entry->size_in_bits, + type_struct_field->type_entry->align_in_bits, + offset_in_bits, 0, type_struct_field->type_entry->di_type); + + element_types[i] = type_struct_field->type_entry->type_ref; + assert(di_element_types[i]); + assert(element_types[i]); + + total_size_in_bits += type_struct_field->type_entry->size_in_bits; + if (first_field_align_in_bits == 0) { + first_field_align_in_bits = type_struct_field->type_entry->align_in_bits; + } + offset_in_bits += type_struct_field->type_entry->size_in_bits; + + } + + LLVMStructSetBody(struct_type->type_ref, element_types, field_count, false); + + struct_type->align_in_bits = first_field_align_in_bits; + struct_type->size_in_bits = total_size_in_bits; + + LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder, + LLVMZigFileToScope(import->di_file), + buf_ptr(&decl_node->data.struct_decl.name), + import->di_file, decl_node->line + 1, struct_type->size_in_bits, struct_type->align_in_bits, 0, + nullptr, di_element_types, field_count, 0, nullptr, ""); + + LLVMZigReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type); + struct_type->di_type = replacement_di_type; +} + + static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) { switch (node->type) { case NodeTypeExternBlock: @@ -414,37 +479,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node; TypeTableEntry *type_entry = struct_codegen->type_entry; - int field_count = node->data.struct_decl.fields.length;; - type_entry->data.structure.field_count = field_count; - type_entry->data.structure.fields = allocate(field_count); - - LLVMTypeRef *element_types = allocate(field_count); - LLVMZigDIType **di_element_types = allocate(field_count); - - uint64_t total_size_in_bits = 0; - - for (int i = 0; i < field_count; i += 1) { - AstNode *field_node = node->data.struct_decl.fields.at(i); - TypeStructField *type_struct_field = &type_entry->data.structure.fields[i]; - type_struct_field->name = &field_node->data.struct_field.name; - type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type); - - total_size_in_bits = type_struct_field->type_entry->size_in_bits; - di_element_types[i] = type_struct_field->type_entry->di_type; - - element_types[i] = type_struct_field->type_entry->type_ref; - } - LLVMStructSetBody(type_entry->type_ref, element_types, field_count, false); - - // TODO re-evaluate this align in bits and size in bits - type_entry->align_in_bits = 0; - type_entry->size_in_bits = total_size_in_bits; - type_entry->di_type = LLVMZigCreateDebugStructType(g->dbuilder, - LLVMZigFileToScope(import->di_file), - buf_ptr(&node->data.struct_decl.name), - import->di_file, node->line + 1, type_entry->size_in_bits, type_entry->align_in_bits, 0, - nullptr, di_element_types, field_count, 0, nullptr, ""); - + resolve_struct_type(g, import, type_entry); break; } case NodeTypeUse: @@ -496,6 +531,11 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { } else { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name)); + entry->data.structure.decl_node = node; + entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder, + LLVMZigTag_DW_structure_type(), buf_ptr(&node->data.struct_decl.name), + LLVMZigFileToScope(import->di_file), import->di_file, node->line + 1); + buf_init_from_buf(&entry->name, name); // put off adding the debug type until we do the full struct body // this type is incomplete until we do another pass diff --git a/src/analyze.hpp b/src/analyze.hpp index 0d4159ea2b..e48a4d28c7 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -39,6 +39,7 @@ struct TypeStructField { }; struct TypeTableEntryStruct { + AstNode *decl_node; bool is_packed; int field_count; TypeStructField *fields; diff --git a/src/codegen.cpp b/src/codegen.cpp index 9adc78a573..3223601de5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -215,8 +215,7 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou /* if (struct_type->id == TypeTableEntryIdPointer) { - add_debug_source_node(g, node); - struct_ptr = LLVMBuildLoad(g->builder, struct_ptr, ""); + zig_panic("TODO pointer field struct access"); } */ diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index e8d49058cf..13e9dc956e 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -161,6 +161,18 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder, uint64_t return reinterpret_cast(di_type); } +LLVMZigDIType *LLVMZigCreateDebugMemberType(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope, + const char *name, LLVMZigDIFile *file, unsigned line, uint64_t size_in_bits, + uint64_t align_in_bits, uint64_t offset_in_bits, unsigned flags, LLVMZigDIType *type) +{ + DIType *di_type = reinterpret_cast(dibuilder)->createMemberType( + reinterpret_cast(scope), + name, + reinterpret_cast(file), + line, size_in_bits, align_in_bits, offset_in_bits, flags, + reinterpret_cast(type)); + return reinterpret_cast(di_type); +} LLVMZigDIType *LLVMZigCreateDebugStructType(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope, const char *name, LLVMZigDIFile *file, unsigned line_number, uint64_t size_in_bits, @@ -186,6 +198,39 @@ LLVMZigDIType *LLVMZigCreateDebugStructType(LLVMZigDIBuilder *dibuilder, LLVMZig return reinterpret_cast(di_type); } +LLVMZigDIType *LLVMZigCreateReplaceableCompositeType(LLVMZigDIBuilder *dibuilder, unsigned tag, + const char *name, LLVMZigDIScope *scope, LLVMZigDIFile *file, unsigned line) +{ + DIType *di_type = reinterpret_cast(dibuilder)->createReplaceableCompositeType( + tag, name, + reinterpret_cast(scope), + reinterpret_cast(file), + line); + return reinterpret_cast(di_type); +} + +void LLVMZigReplaceTemporary(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type, + LLVMZigDIType *replacement) +{ + reinterpret_cast(dibuilder)->replaceTemporary( + TempDIType(reinterpret_cast(type)), + reinterpret_cast(replacement)); +} + +void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type, + LLVMZigDIType **types_array, int types_array_len) +{ + SmallVector fields; + for (int i = 0; i < types_array_len; i += 1) { + DIType *ditype = reinterpret_cast(types_array[i]); + fields.push_back(ditype); + } + DICompositeType *composite_type = (DICompositeType*)reinterpret_cast(type); + reinterpret_cast(dibuilder)->replaceArrays( + composite_type, + reinterpret_cast(dibuilder)->getOrCreateArray(fields)); +} + LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped, LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags) { @@ -226,6 +271,10 @@ unsigned LLVMZigTag_DW_arg_variable(void) { return dwarf::DW_TAG_arg_variable; } +unsigned LLVMZigTag_DW_structure_type(void) { + return dwarf::DW_TAG_structure_type; +} + LLVMZigDIBuilder *LLVMZigCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved); return reinterpret_cast(di_builder); @@ -286,6 +335,11 @@ LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram) { return reinterpret_cast(scope); } +LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type) { + DIScope *scope = reinterpret_cast(type); + return reinterpret_cast(scope); +} + LLVMZigDICompileUnit *LLVMZigCreateCompileUnit(LLVMZigDIBuilder *dibuilder, unsigned lang, const char *file, const char *dir, const char *producer, bool is_optimized, const char *flags, unsigned runtime_version, const char *split_name, diff --git a/src/zig_llvm.hpp b/src/zig_llvm.hpp index 8cc1bb5d7b..2e7747c12d 100644 --- a/src/zig_llvm.hpp +++ b/src/zig_llvm.hpp @@ -55,6 +55,19 @@ LLVMZigDIType *LLVMZigCreateDebugStructType(LLVMZigDIBuilder *dibuilder, LLVMZig LLVMZigDIType **types_array, int types_array_len, unsigned run_time_lang, LLVMZigDIType *vtable_holder, const char *unique_id); +LLVMZigDIType *LLVMZigCreateDebugMemberType(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope, + const char *name, LLVMZigDIFile *file, unsigned line, uint64_t size_in_bits, + uint64_t align_in_bits, uint64_t offset_in_bits, unsigned flags, LLVMZigDIType *type); + +LLVMZigDIType *LLVMZigCreateReplaceableCompositeType(LLVMZigDIBuilder *dibuilder, unsigned tag, + const char *name, LLVMZigDIScope *scope, LLVMZigDIFile *file, unsigned line); + +void LLVMZigReplaceTemporary(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type, + LLVMZigDIType *replacement); + +void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type, + LLVMZigDIType **types_array, int types_array_len); + LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped, LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags); @@ -64,6 +77,7 @@ unsigned LLVMZigEncoding_DW_ATE_float(void); unsigned LLVMZigLang_DW_LANG_C99(void); unsigned LLVMZigTag_DW_auto_variable(void); unsigned LLVMZigTag_DW_arg_variable(void); +unsigned LLVMZigTag_DW_structure_type(void); LLVMZigDIBuilder *LLVMZigCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); @@ -73,6 +87,7 @@ LLVMZigDIScope *LLVMZigLexicalBlockToScope(LLVMZigDILexicalBlock *lexical_block) LLVMZigDIScope *LLVMZigCompileUnitToScope(LLVMZigDICompileUnit *compile_unit); LLVMZigDIScope *LLVMZigFileToScope(LLVMZigDIFile *difile); LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram); +LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type); LLVMZigDILocalVariable *LLVMZigCreateLocalVariable(LLVMZigDIBuilder *dbuilder, unsigned tag, LLVMZigDIScope *scope, const char *name, LLVMZigDIFile *file, unsigned line_no,