From 9c9ea935191190471c1b2fd30c8cffde74421456 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 7 Dec 2015 22:11:04 -0700 Subject: [PATCH] integrate debug scopes with block context --- src/analyze.cpp | 12 ++++------ src/codegen.cpp | 56 +++++++++++++++++++++++++------------------ src/semantic_info.hpp | 12 +++++++++- src/zig_llvm.cpp | 33 ++++++++++++++++++------- src/zig_llvm.hpp | 7 ++++++ 5 files changed, 79 insertions(+), 41 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index f8fe260edb..c1af7b1557 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -443,10 +443,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, TypeTableEntry *expected_type, AstNode *node) { TypeTableEntry *return_type = nullptr; + assert(!node->codegen_node); + node->codegen_node = allocate(1); switch (node->type) { case NodeTypeBlock: { BlockContext *child_context = new_block_context(node, context); + node->codegen_node->data.block_node.block_context = child_context; return_type = g->builtin_types.entry_void; for (int i = 0; i < node->data.block.statements.length; i += 1) { AstNode *child = node->data.block.statements.at(i); @@ -538,8 +541,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, FnTableEntry *fn_table_entry = get_context_fn_entry(context); auto table_entry = fn_table_entry->label_table.maybe_get(&node->data.go_to.name); if (table_entry) { - assert(!node->codegen_node); - node->codegen_node = allocate(1); node->codegen_node->data.label_entry = table_entry->value; table_entry->value->used = true; } else { @@ -792,12 +793,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, assert(return_type); check_type_compatibility(g, node, expected_type, return_type); - if (node->codegen_node) { - assert(node->type == NodeTypeGoto); - } else { - assert(node->type != NodeTypeGoto); - node->codegen_node = allocate(1); - } node->codegen_node->expr_node.type_entry = return_type; node->codegen_node->expr_node.block_context = context; @@ -837,6 +832,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, variable_entry->type = type; variable_entry->is_const = true; variable_entry->decl_node = param_decl_node; + variable_entry->arg_index = i; LocalVariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); if (!existing_entry) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 49254e9d34..b72303a040 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -102,8 +102,8 @@ static int count_non_void_params(CodeGen *g, ZigList *params) { } static void add_debug_source_node(CodeGen *g, AstNode *node) { - // TODO g->block_scopes.last() is not always correct and should probably integrate with BlockContext - LLVMZigSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, g->block_scopes.last()); + LLVMZigSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, + g->cur_block_context->di_scope); } static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) { @@ -484,13 +484,7 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) { static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { assert(block_node->type == NodeTypeBlock); - ImportTableEntry *import = g->cur_fn->import_entry; - - LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, g->block_scopes.last(), - import->di_file, block_node->line + 1, block_node->column + 1); - g->block_scopes.append(LLVMZigLexicalBlockToScope(di_block)); - - add_debug_source_node(g, block_node); + g->cur_block_context = block_node->codegen_node->data.block_node.block_context; LLVMValueRef return_value; for (int i = 0; i < block_node->data.block.statements.length; i += 1) { @@ -506,8 +500,6 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i } } - g->block_scopes.pop(); - return return_value; } @@ -654,9 +646,6 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro static void do_code_gen(CodeGen *g) { assert(!g->errors.length); - g->block_scopes.append(LLVMZigCompileUnitToScope(g->compile_unit)); - - // Generate function prototypes for (int i = 0; i < g->fn_protos.length; i += 1) { FnTableEntry *fn_table_entry = g->fn_protos.at(i); @@ -718,8 +707,6 @@ static void do_code_gen(CodeGen *g) { create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage, is_definition, scope_line, flags, is_optimized, fn); - g->block_scopes.append(LLVMZigSubprogramToScope(subprogram)); - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry"); LLVMPositionBuilderAtEnd(g->builder, entry_block); @@ -728,6 +715,9 @@ static void do_code_gen(CodeGen *g) { FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node; assert(codegen_fn_def); + + codegen_fn_def->block_context->di_scope = LLVMZigSubprogramToScope(subprogram); + int non_void_param_count = count_non_void_params(g, &fn_proto->params); assert(non_void_param_count == (int)LLVMCountParams(fn)); LLVMValueRef *params = allocate(non_void_param_count); @@ -746,15 +736,22 @@ static void do_code_gen(CodeGen *g) { build_label_blocks(g, fn_def_node->data.fn_def.body); + // Set up debug info for blocks and variables and // allocate all local variables for (int i = 0; i < codegen_fn_def->all_block_contexts.length; i += 1) { BlockContext *block_context = codegen_fn_def->all_block_contexts.at(i); - // skip the block context for function parameters - if (block_context->node->type == NodeTypeFnDef) { - continue; + if (block_context->parent) { + LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, + block_context->parent->di_scope, + import->di_file, + block_context->node->line + 1, + block_context->node->column + 1); + block_context->di_scope = LLVMZigLexicalBlockToScope(di_block); } + g->cur_block_context = block_context; + auto it = block_context->variable_table.entry_iterator(); for (;;) { auto *entry = it.next(); @@ -765,16 +762,29 @@ static void do_code_gen(CodeGen *g) { if (var->type == g->builtin_types.entry_void) continue; - add_debug_source_node(g, var->decl_node); - var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name)); + unsigned tag; + unsigned arg_no; + if (block_context->node->type == NodeTypeFnDef) { + tag = LLVMZigTag_DW_arg_variable(); + arg_no = var->arg_index + 1; + } else { + tag = LLVMZigTag_DW_auto_variable(); + arg_no = 0; + + add_debug_source_node(g, var->decl_node); + var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name)); + } + + var->di_loc_var = LLVMZigCreateLocalVariable(g->dbuilder, tag, + block_context->di_scope, buf_ptr(&var->name), + import->di_file, var->decl_node->line + 1, + var->type->di_type, !g->strip_debug_symbols, 0, arg_no); } } TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type; gen_block(g, fn_def_node->data.fn_def.body, implicit_return_type); - g->block_scopes.pop(); - } assert(!g->errors.length); diff --git a/src/semantic_info.hpp b/src/semantic_info.hpp index 325c47cc2f..ec5aec5bfc 100644 --- a/src/semantic_info.hpp +++ b/src/semantic_info.hpp @@ -14,6 +14,7 @@ #include "errmsg.hpp" struct FnTableEntry; +struct BlockContext; struct TypeTableEntry { LLVMTypeRef type_ref; @@ -96,7 +97,6 @@ struct CodeGen { bool is_native_target; Buf *root_source_dir; Buf *root_out_name; - ZigList block_scopes; // The function definitions this module includes. There must be a corresponding // fn_protos entry. @@ -108,6 +108,7 @@ struct CodeGen { OutType out_type; FnTableEntry *cur_fn; LLVMBasicBlockRef cur_basic_block; + BlockContext *cur_block_context; bool c_stdint_used; AstNode *root_export_decl; int version_major; @@ -125,6 +126,8 @@ struct LocalVariableTableEntry { bool is_const; bool is_ptr; // if true, value_ref is a pointer AstNode *decl_node; + LLVMZigDILocalVariable *di_loc_var; + int arg_index; }; struct BlockContext { @@ -132,6 +135,7 @@ struct BlockContext { BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef BlockContext *parent; // nullptr when this is the root HashMap variable_table; + LLVMZigDIScope *di_scope; }; struct TypeNode { @@ -146,6 +150,7 @@ struct FnDefNode { TypeTableEntry *implicit_return_type; BlockContext *block_context; bool skip; + // Required to be a pre-order traversal of the AST. (parents must come before children) ZigList all_block_contexts; }; @@ -160,6 +165,10 @@ struct AssignNode { LocalVariableTableEntry *var_entry; }; +struct BlockNode { + BlockContext *block_context; +}; + struct CodeGenNode { union { TypeNode type_node; // for NodeTypeType @@ -167,6 +176,7 @@ struct CodeGenNode { FnProtoNode fn_proto_node; // for NodeTypeFnProto LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign + BlockNode block_node; // for NodeTypeBlock } data; ExprNode expr_node; // for all the expression nodes }; diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 6e8f571030..bef47b07fe 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -189,6 +189,14 @@ unsigned LLVMZigLang_DW_LANG_C99(void) { return dwarf::DW_LANG_C99; } +unsigned LLVMZigTag_DW_auto_variable(void) { + return dwarf::DW_TAG_auto_variable; +} + +unsigned LLVMZigTag_DW_arg_variable(void) { + return dwarf::DW_TAG_arg_variable; +} + LLVMZigDIBuilder *LLVMZigCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved); return reinterpret_cast(di_builder); @@ -211,16 +219,23 @@ LLVMZigDILexicalBlock *LLVMZigCreateLexicalBlock(LLVMZigDIBuilder *dbuilder, LLV return reinterpret_cast(result); } -/* -LLVMZigDILocalVariable * - DILocalVariable *createLocalVariable(unsigned Tag, DIScope *Scope, - StringRef Name, DIFile *File, - unsigned LineNo, DIType *Ty, - bool AlwaysPreserve = false, - unsigned Flags = 0, - unsigned ArgNo = 0); - */ +LLVMZigDILocalVariable *LLVMZigCreateLocalVariable(LLVMZigDIBuilder *dbuilder, unsigned tag, + LLVMZigDIScope *scope, const char *name, LLVMZigDIFile *file, unsigned line_no, + LLVMZigDIType *type, bool always_preserve, unsigned flags, unsigned arg_no) +{ + DILocalVariable *result = reinterpret_cast(dbuilder)->createLocalVariable( + tag, + reinterpret_cast(scope), + name, + reinterpret_cast(file), + line_no, + reinterpret_cast(type), + always_preserve, + flags, + arg_no); + return reinterpret_cast(result); +} LLVMZigDIScope *LLVMZigLexicalBlockToScope(LLVMZigDILexicalBlock *lexical_block) { DIScope *scope = reinterpret_cast(lexical_block); diff --git a/src/zig_llvm.hpp b/src/zig_llvm.hpp index 604b3db364..8ad63c77c1 100644 --- a/src/zig_llvm.hpp +++ b/src/zig_llvm.hpp @@ -22,6 +22,7 @@ struct LLVMZigDIFile; struct LLVMZigDILexicalBlock; struct LLVMZigDISubprogram; struct LLVMZigDISubroutineType; +struct LLVMZigDILocalVariable; struct LLVMZigInsertionPoint; void LLVMZigInitializeLoopStrengthReducePass(LLVMPassRegistryRef R); @@ -54,6 +55,8 @@ LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder unsigned LLVMZigEncoding_DW_ATE_unsigned(void); unsigned LLVMZigEncoding_DW_ATE_signed(void); unsigned LLVMZigLang_DW_LANG_C99(void); +unsigned LLVMZigTag_DW_auto_variable(void); +unsigned LLVMZigTag_DW_arg_variable(void); LLVMZigDIBuilder *LLVMZigCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); @@ -64,6 +67,10 @@ LLVMZigDIScope *LLVMZigCompileUnitToScope(LLVMZigDICompileUnit *compile_unit); LLVMZigDIScope *LLVMZigFileToScope(LLVMZigDIFile *difile); LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram); +LLVMZigDILocalVariable *LLVMZigCreateLocalVariable(LLVMZigDIBuilder *dbuilder, unsigned tag, + LLVMZigDIScope *scope, const char *name, LLVMZigDIFile *file, unsigned line_no, + LLVMZigDIType *type, bool always_preserve, unsigned flags, unsigned arg_no); + LLVMZigDILexicalBlock *LLVMZigCreateLexicalBlock(LLVMZigDIBuilder *dbuilder, LLVMZigDIScope *scope, LLVMZigDIFile *file, unsigned line, unsigned col);