diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-03-18 11:24:58 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-03-18 11:28:43 -0400 |
| commit | fa7c64ccd511703fef9971c4d07c447c9aeda49c (patch) | |
| tree | 6f41eb742160ec1584b6adb719ec1327f9e3c831 /src | |
| parent | af536ac343564e5120f99cbf3b7fc9efa984eb93 (diff) | |
| download | zig-fa7c64ccd511703fef9971c4d07c447c9aeda49c.tar.gz zig-fa7c64ccd511703fef9971c4d07c447c9aeda49c.zip | |
lazy analysis of top level declarations
previously, we had lazy analysis of top level declarations,
but if a declaration was referenced within a compile-time
if or switch statement, that would still add the top
level declaration to the resolution queue.
now we have a declref ir instruction, which is only resolved
if we analyze the instruction. this takes into account comptime
branching.
closes #270
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 14 | ||||
| -rw-r--r-- | src/codegen.cpp | 1 | ||||
| -rw-r--r-- | src/ir.cpp | 157 | ||||
| -rw-r--r-- | src/ir_print.cpp | 10 |
4 files changed, 127 insertions, 55 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 48777b6df0..b3faff2212 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1610,6 +1610,12 @@ struct IrBasicBlock { IrInstruction *must_be_comptime_source_instr; }; +struct LVal { + bool is_ptr; + bool is_const; + bool is_volatile; +}; + enum IrInstructionId { IrInstructionIdInvalid, IrInstructionIdBr, @@ -1701,6 +1707,7 @@ enum IrInstructionId { IrInstructionIdCanImplicitCast, IrInstructionIdSetGlobalAlign, IrInstructionIdSetGlobalSection, + IrInstructionIdDeclRef, }; struct IrInstruction { @@ -2421,6 +2428,13 @@ struct IrInstructionSetGlobalSection { IrInstruction *value; }; +struct IrInstructionDeclRef { + IrInstruction base; + + Tld *tld; + LVal lval; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index 5456fbce3d..a1dac1cca1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2519,6 +2519,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdCanImplicitCast: case IrInstructionIdSetGlobalAlign: case IrInstructionIdSetGlobalSection: + case IrInstructionIdDeclRef: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); diff --git a/src/ir.cpp b/src/ir.cpp index 79647cdb97..0abf051ad3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -44,12 +44,6 @@ struct IrAnalyze { IrBasicBlock *const_predecessor_bb; }; -struct LVal { - bool is_ptr; - bool is_const; - bool is_volatile; -}; - static const LVal LVAL_NONE = { false, false, false }; static const LVal LVAL_PTR = { true, false, false }; @@ -534,6 +528,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection return IrInstructionIdSetGlobalSection; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) { + return IrInstructionIdDeclRef; +} + template<typename T> static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -686,14 +684,20 @@ static IrInstruction *ir_build_const_type(IrBuilder *irb, Scope *scope, AstNode return instruction; } -static IrInstruction *ir_build_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry) { - IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); +static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry) { + IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb, scope, source_node); const_instruction->base.value.type = fn_entry->type_entry; const_instruction->base.value.special = ConstValSpecialStatic; const_instruction->base.value.data.x_fn = fn_entry; return &const_instruction->base; } +static IrInstruction *ir_build_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry) { + IrInstruction *instruction = ir_create_const_fn(irb, scope, source_node, fn_entry); + ir_instruction_append(irb->current_basic_block, instruction); + return instruction; +} + static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ImportTableEntry *import) { IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); const_instruction->base.value.type = irb->codegen->builtin_types.entry_namespace; @@ -2088,6 +2092,17 @@ static IrInstruction *ir_build_set_global_section(IrBuilder *irb, Scope *scope, return &instruction->base; } +static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, + Tld *tld, LVal lval) +{ + IrInstructionDeclRef *instruction = ir_build_instruction<IrInstructionDeclRef>( + irb, scope, source_node); + instruction->tld = tld; + instruction->lval = lval; + + return &instruction->base; +} + static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { return nullptr; } @@ -2727,6 +2742,10 @@ static IrInstruction *ir_instruction_setglobalsection_get_dep(IrInstructionSetGl } } +static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) { + return nullptr; +} + static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -2909,6 +2928,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_setglobalalign_get_dep((IrInstructionSetGlobalAlign *) instruction, index); case IrInstructionIdSetGlobalSection: return ir_instruction_setglobalsection_get_dep((IrInstructionSetGlobalSection *) instruction, index); + case IrInstructionIdDeclRef: + return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index); } zig_unreachable(); } @@ -3574,52 +3595,6 @@ static IrInstruction *ir_gen_var_literal(IrBuilder *irb, Scope *scope, AstNode * return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_var); } -static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld *tld, - LVal lval, Scope *scope) -{ - resolve_top_level_decl(irb->codegen, tld, lval.is_ptr); - if (tld->resolution == TldResolutionInvalid) - return irb->codegen->invalid_instruction; - - switch (tld->id) { - case TldIdContainer: - zig_unreachable(); - case TldIdVar: - { - TldVar *tld_var = (TldVar *)tld; - VariableTableEntry *var = tld_var->var; - IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, source_node, var, - !lval.is_ptr || lval.is_const, lval.is_ptr && lval.is_volatile); - if (lval.is_ptr) - return var_ptr; - else - return ir_build_load_ptr(irb, scope, source_node, var_ptr); - } - case TldIdFn: - { - TldFn *tld_fn = (TldFn *)tld; - FnTableEntry *fn_entry = tld_fn->fn_entry; - assert(fn_entry->type_entry); - IrInstruction *ref_instruction = ir_build_const_fn(irb, scope, source_node, fn_entry); - if (lval.is_ptr) - return ir_build_ref(irb, scope, source_node, ref_instruction, true, false); - else - return ref_instruction; - } - case TldIdTypeDef: - { - TldTypeDef *tld_typedef = (TldTypeDef *)tld; - TypeTableEntry *typedef_type = tld_typedef->type_entry; - IrInstruction *ref_instruction = ir_build_const_type(irb, scope, source_node, typedef_type); - if (lval.is_ptr) - return ir_build_ref(irb, scope, source_node, ref_instruction, true, false); - else - return ref_instruction; - } - } - zig_unreachable(); -} - static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { assert(node->type == NodeTypeSymbol); @@ -3656,7 +3631,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, Tld *tld = find_decl(irb->codegen, scope, variable_name); if (tld) - return ir_gen_decl_ref(irb, node, tld, lval, scope); + return ir_build_decl_ref(irb, scope, node, tld, lval); if (node->owner->any_imports_failed) { // skip the error message since we had a failing import in this file @@ -12152,6 +12127,75 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira, return ira->codegen->builtin_types.entry_bool; } +static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira, + IrInstructionDeclRef *instruction) +{ + Tld *tld = instruction->tld; + LVal lval = instruction->lval; + + resolve_top_level_decl(ira->codegen, tld, lval.is_ptr); + if (tld->resolution == TldResolutionInvalid) + return ira->codegen->builtin_types.entry_invalid; + + switch (tld->id) { + case TldIdContainer: + zig_unreachable(); + case TldIdVar: + { + TldVar *tld_var = (TldVar *)tld; + VariableTableEntry *var = tld_var->var; + + IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var, + !lval.is_ptr || lval.is_const, lval.is_ptr && lval.is_volatile); + if (type_is_invalid(var_ptr->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + if (lval.is_ptr) { + ir_link_new_instruction(var_ptr, &instruction->base); + return var_ptr->value.type; + } else { + IrInstruction *loaded_instr = ir_get_deref(ira, &instruction->base, var_ptr); + ir_link_new_instruction(loaded_instr, &instruction->base); + return loaded_instr->value.type; + } + } + case TldIdFn: + { + TldFn *tld_fn = (TldFn *)tld; + FnTableEntry *fn_entry = tld_fn->fn_entry; + assert(fn_entry->type_entry); + + IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, fn_entry); + if (lval.is_ptr) { + IrInstruction *ptr_instr = ir_get_ref(ira, &instruction->base, ref_instruction, true, false); + ir_link_new_instruction(ptr_instr, &instruction->base); + return ptr_instr->value.type; + } else { + ir_link_new_instruction(ref_instruction, &instruction->base); + return ref_instruction->value.type; + } + } + case TldIdTypeDef: + { + TldTypeDef *tld_typedef = (TldTypeDef *)tld; + TypeTableEntry *typedef_type = tld_typedef->type_entry; + + IrInstruction *ref_instruction = ir_create_const_type(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, typedef_type); + if (lval.is_ptr) { + IrInstruction *ptr_inst = ir_get_ref(ira, &instruction->base, ref_instruction, true, false); + ir_link_new_instruction(ptr_inst, &instruction->base); + return ptr_inst->value.type; + } else { + ir_link_new_instruction(ref_instruction, &instruction->base); + return ref_instruction->value.type; + } + } + } + zig_unreachable(); +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -12317,6 +12361,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_test_type(ira, (IrInstructionTestType *)instruction); case IrInstructionIdCanImplicitCast: return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction); + case IrInstructionIdDeclRef: + return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction); case IrInstructionIdMaybeWrap: case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: @@ -12495,6 +12541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTestType: case IrInstructionIdTypeName: case IrInstructionIdCanImplicitCast: + case IrInstructionIdDeclRef: return false; case IrInstructionIdAsm: { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b5f5a16983..8365aec050 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -849,6 +849,13 @@ static void ir_print_set_global_section(IrPrint *irp, IrInstructionSetGlobalSect fprintf(irp->f, ")"); } +static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) { + const char *ptr_str = instruction->lval.is_ptr ? "ptr " : ""; + const char *const_str = instruction->lval.is_const ? "const " : ""; + const char *volatile_str = instruction->lval.is_volatile ? "volatile " : ""; + fprintf(irp->f, "declref %s%s%s%s", const_str, volatile_str, ptr_str, buf_ptr(instruction->tld->name)); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1121,6 +1128,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSetGlobalSection: ir_print_set_global_section(irp, (IrInstructionSetGlobalSection *)instruction); break; + case IrInstructionIdDeclRef: + ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction); + break; } fprintf(irp->f, "\n"); } |
