authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-18 18:23:46-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-18 18:23:46-05:00
logf12fbce0f51d58b429afd8a359aeb8a3b27a4eb0
treefbbdda77efc779ee473d898bf34933ee67439440
parent4816121e008aa4c28241a94253b0c4a2b7b6ba7c

IR: memoize compile-time evaluated fn invocations


4 files changed, 69 insertions(+), 7 deletions(-)

src/all_types.hpp+4
...@@ -1067,6 +1067,9 @@ struct BuiltinFnEntry {...@@ -1067,6 +1067,9 @@ struct BuiltinFnEntry {
1067 LLVMValueRef fn_val;1067 LLVMValueRef fn_val;
1068};1068};
10691069
1070uint32_t fn_eval_hash(Scope*);
1071bool fn_eval_eql(Scope *a, Scope *b);
1072
1070struct CodeGen {1073struct CodeGen {
1071 LLVMModuleRef module;1074 LLVMModuleRef module;
1072 ZigList<ErrorMsg*> errors;1075 ZigList<ErrorMsg*> errors;
...@@ -1085,6 +1088,7 @@ struct CodeGen {...@@ -1085,6 +1088,7 @@ struct CodeGen {
1085 HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;1088 HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
1086 HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;1089 HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
1087 HashMap<GenericFnTypeId *, FnTableEntry *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;1090 HashMap<GenericFnTypeId *, FnTableEntry *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
1091 HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
10881092
1089 ZigList<ImportTableEntry *> import_queue;1093 ZigList<ImportTableEntry *> import_queue;
1090 size_t import_queue_index;1094 size_t import_queue_index;
src/analyze.cpp+48
...@@ -2693,6 +2693,54 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {...@@ -2693,6 +2693,54 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
2693 return true;2693 return true;
2694}2694}
26952695
2696uint32_t fn_eval_hash(Scope* scope) {
2697 uint32_t result = 0;
2698 while (scope) {
2699 if (scope->id == ScopeIdVarDecl) {
2700 ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
2701 result += hash_const_val(var_scope->var->type, var_scope->var->value);
2702 } else if (scope->id == ScopeIdFnDef) {
2703 ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
2704 result += hash_ptr(fn_scope->fn_entry);
2705 return result;
2706 } else {
2707 zig_unreachable();
2708 }
2709
2710 scope = scope->parent;
2711 }
2712 zig_unreachable();
2713}
2714
2715bool fn_eval_eql(Scope *a, Scope *b) {
2716 while (a && b) {
2717 if (a->id != b->id)
2718 return false;
2719
2720 if (a->id == ScopeIdVarDecl) {
2721 ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a;
2722 ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b;
2723 if (a_var_scope->var->type != b_var_scope->var->type)
2724 return false;
2725 if (!const_values_equal(a_var_scope->var->value, b_var_scope->var->value, a_var_scope->var->type))
2726 return false;
2727 } else if (a->id == ScopeIdFnDef) {
2728 ScopeFnDef *a_fn_scope = (ScopeFnDef *)a;
2729 ScopeFnDef *b_fn_scope = (ScopeFnDef *)b;
2730 if (a_fn_scope->fn_entry != b_fn_scope->fn_entry)
2731 return false;
2732
2733 return true;
2734 } else {
2735 zig_unreachable();
2736 }
2737
2738 a = a->parent;
2739 b = b->parent;
2740 }
2741 return false;
2742}
2743
2696bool type_has_bits(TypeTableEntry *type_entry) {2744bool type_has_bits(TypeTableEntry *type_entry) {
2697 assert(type_entry);2745 assert(type_entry);
2698 assert(type_entry->id != TypeTableEntryIdInvalid);2746 assert(type_entry->id != TypeTableEntryIdInvalid);
src/codegen.cpp+1
...@@ -61,6 +61,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {...@@ -61,6 +61,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
61 g->fn_type_table.init(32);61 g->fn_type_table.init(32);
62 g->error_table.init(16);62 g->error_table.init(16);
63 g->generic_table.init(16);63 g->generic_table.init(16);
64 g->memoized_fn_eval_table.init(16);
64 g->is_release_build = false;65 g->is_release_build = false;
65 g->is_test_build = false;66 g->is_test_build = false;
66 g->want_h_file = true;67 g->want_h_file = true;
src/ir.cpp+16-7
...@@ -6049,13 +6049,22 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -6049,13 +6049,22 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
6049 if (return_type->id == TypeTableEntryIdInvalid)6049 if (return_type->id == TypeTableEntryIdInvalid)
6050 return ira->codegen->builtin_types.entry_invalid;6050 return ira->codegen->builtin_types.entry_invalid;
60516051
6052 // Analyze the fn body block like any other constant expression.6052 IrInstruction *result;
6053 AstNode *body_node = fn_entry->fn_def_node->data.fn_def.body;6053
6054 IrInstruction *result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type,6054 auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope);
6055 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,6055 if (entry) {
6056 nullptr, call_instruction->base.source_node, nullptr);6056 result = entry->value;
6057 if (result->type_entry->id == TypeTableEntryIdInvalid)6057 } else {
6058 return ira->codegen->builtin_types.entry_invalid;6058 // Analyze the fn body block like any other constant expression.
6059 AstNode *body_node = fn_entry->fn_def_node->data.fn_def.body;
6060 result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type,
6061 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
6062 nullptr, call_instruction->base.source_node, nullptr);
6063 if (result->type_entry->id == TypeTableEntryIdInvalid)
6064 return ira->codegen->builtin_types.entry_invalid;
6065
6066 ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
6067 }
60596068
6060 ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base,6069 ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base,
6061 result->static_value.depends_on_compile_var);6070 result->static_value.depends_on_compile_var);