| author | |
| committer | |
| log | 0541532ed6cf5a32b57a4a3f74e6d3a1699223a7 |
| tree | 3359c1bc68ea224c55e9d2ffb5261eff6f7c2b9f |
| parent | 363606d87b3f45c7f62969f85062e2a7b1b4b5dc |
7 files changed, 301 insertions(+), 75 deletions(-)
src/all_types.hpp+15-2| ... | @@ -726,6 +726,19 @@ struct FnTypeParamInfo { | ... | @@ -726,6 +726,19 @@ struct FnTypeParamInfo { |
| 726 | TypeTableEntry *type; | 726 | TypeTableEntry *type; |
| 727 | }; | 727 | }; |
| 728 | 728 | ||
| 729 | struct GenericParamValue { | ||
| 730 | TypeTableEntry *type; | ||
| 731 | ConstExprValue *value; | ||
| 732 | }; | ||
| 733 | |||
| 734 | struct GenericFnTypeId { | ||
| 735 | FnTableEntry *fn_entry; | ||
| 736 | GenericParamValue *params; | ||
| 737 | size_t param_count; | ||
| 738 | }; | ||
| 739 | |||
| 740 | uint32_t generic_fn_type_id_hash(GenericFnTypeId *id); | ||
| 741 | bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b); | ||
| 729 | 742 | ||
| 730 | struct FnTypeId { | 743 | struct FnTypeId { |
| 731 | TypeTableEntry *return_type; | 744 | TypeTableEntry *return_type; |
| ... | @@ -957,7 +970,6 @@ struct FnTableEntry { | ... | @@ -957,7 +970,6 @@ struct FnTableEntry { |
| 957 | ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls | 970 | ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls |
| 958 | Scope *child_scope; // parent is scope for last parameter | 971 | Scope *child_scope; // parent is scope for last parameter |
| 959 | ScopeBlock *def_scope; // parent is child_scope | 972 | ScopeBlock *def_scope; // parent is child_scope |
| 960 | ImportTableEntry *import_entry; | ||
| 961 | Buf symbol_name; | 973 | Buf symbol_name; |
| 962 | TypeTableEntry *type_entry; // function type | 974 | TypeTableEntry *type_entry; // function type |
| 963 | TypeTableEntry *implicit_return_type; | 975 | TypeTableEntry *implicit_return_type; |
| ... | @@ -969,6 +981,7 @@ struct FnTableEntry { | ... | @@ -969,6 +981,7 @@ struct FnTableEntry { |
| 969 | IrExecutable ir_executable; | 981 | IrExecutable ir_executable; |
| 970 | IrExecutable analyzed_executable; | 982 | IrExecutable analyzed_executable; |
| 971 | size_t prealloc_bbc; | 983 | size_t prealloc_bbc; |
| 984 | AstNode **param_source_nodes; | ||
| 972 | 985 | ||
| 973 | AstNode *fn_no_inline_set_node; | 986 | AstNode *fn_no_inline_set_node; |
| 974 | AstNode *fn_export_set_node; | 987 | AstNode *fn_export_set_node; |
| ... | @@ -1050,6 +1063,7 @@ struct CodeGen { | ... | @@ -1050,6 +1063,7 @@ struct CodeGen { |
| 1050 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table; | 1063 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table; |
| 1051 | HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table; | 1064 | HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table; |
| 1052 | HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table; | 1065 | HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table; |
| 1066 | HashMap<GenericFnTypeId *, FnTableEntry *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table; | ||
| 1053 | 1067 | ||
| 1054 | ZigList<ImportTableEntry *> import_queue; | 1068 | ZigList<ImportTableEntry *> import_queue; |
| 1055 | size_t import_queue_index; | 1069 | size_t import_queue_index; |
| ... | @@ -1201,7 +1215,6 @@ struct VariableTableEntry { | ... | @@ -1201,7 +1215,6 @@ struct VariableTableEntry { |
| 1201 | Scope *parent_scope; | 1215 | Scope *parent_scope; |
| 1202 | Scope *child_scope; | 1216 | Scope *child_scope; |
| 1203 | LLVMValueRef param_value_ref; | 1217 | LLVMValueRef param_value_ref; |
| 1204 | bool force_depends_on_compile_var; | ||
| 1205 | bool shadowable; | 1218 | bool shadowable; |
| 1206 | size_t mem_slot_index; | 1219 | size_t mem_slot_index; |
| 1207 | size_t ref_count; | 1220 | size_t ref_count; |
src/analyze.cpp+92-36| ... | @@ -907,22 +907,25 @@ static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -907,22 +907,25 @@ static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 907 | return fn_type; | 907 | return fn_type; |
| 908 | } | 908 | } |
| 909 | 909 | ||
| 910 | static TypeTableEntry *analyze_fn_type(CodeGen *g, TldFn *tld_fn) { | 910 | void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node) { |
| 911 | AstNode *proto_node = tld_fn->base.source_node; | ||
| 912 | assert(proto_node->type == NodeTypeFnProto); | 911 | assert(proto_node->type == NodeTypeFnProto); |
| 913 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | 912 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 914 | 913 | ||
| 915 | FnTypeId fn_type_id = {0}; | 914 | fn_type_id->is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport); |
| 916 | fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport); | 915 | fn_type_id->is_naked = fn_proto->is_nakedcc; |
| 917 | fn_type_id.is_naked = fn_proto->is_nakedcc; | 916 | fn_type_id->is_cold = fn_proto->is_coldcc; |
| 918 | fn_type_id.is_cold = fn_proto->is_coldcc; | 917 | fn_type_id->param_count = fn_proto->params.length; |
| 919 | fn_type_id.param_count = fn_proto->params.length; | 918 | fn_type_id->param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id->param_count); |
| 920 | fn_type_id.param_info = allocate_nonzero<FnTypeParamInfo>(fn_type_id.param_count); | 919 | fn_type_id->next_param_index = 0; |
| 921 | fn_type_id.next_param_index = 0; | 920 | fn_type_id->is_var_args = fn_proto->is_var_args; |
| 922 | fn_type_id.is_var_args = fn_proto->is_var_args; | 921 | } |
| 923 | 922 | ||
| 924 | FnTableEntry *fn_entry = tld_fn->fn_entry; | 923 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) { |
| 925 | Scope *child_scope = fn_entry->fndef_scope ? &fn_entry->fndef_scope->base : tld_fn->base.parent_scope; | 924 | assert(proto_node->type == NodeTypeFnProto); |
| 925 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | ||
| 926 | |||
| 927 | FnTypeId fn_type_id = {0}; | ||
| 928 | init_fn_type_id(&fn_type_id, proto_node); | ||
| 926 | 929 | ||
| 927 | for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { | 930 | for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { |
| 928 | AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); | 931 | AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); |
| ... | @@ -939,10 +942,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, TldFn *tld_fn) { | ... | @@ -939,10 +942,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, TldFn *tld_fn) { |
| 939 | return get_generic_fn_type(g, &fn_type_id); | 942 | return get_generic_fn_type(g, &fn_type_id); |
| 940 | } | 943 | } |
| 941 | 944 | ||
| 942 | if (fn_entry && buf_len(param_node->data.param_decl.name) == 0) { | ||
| 943 | add_node_error(g, param_node, buf_sprintf("missing parameter name")); | ||
| 944 | } | ||
| 945 | |||
| 946 | TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); | 945 | TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); |
| 947 | 946 | ||
| 948 | switch (type_entry->id) { | 947 | switch (type_entry->id) { |
| ... | @@ -1366,6 +1365,23 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { | ... | @@ -1366,6 +1365,23 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { |
| 1366 | } | 1365 | } |
| 1367 | } | 1366 | } |
| 1368 | 1367 | ||
| 1368 | FnTableEntry *create_fn(CodeGen *g, AstNode *proto_node) { | ||
| 1369 | assert(proto_node->type == NodeTypeFnProto); | ||
| 1370 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | ||
| 1371 | |||
| 1372 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); | ||
| 1373 | fn_table_entry->analyzed_executable.backward_branch_count = &fn_table_entry->prealloc_bbc; | ||
| 1374 | fn_table_entry->analyzed_executable.backward_branch_quota = default_backward_branch_quota; | ||
| 1375 | fn_table_entry->analyzed_executable.fn_entry = fn_table_entry; | ||
| 1376 | fn_table_entry->ir_executable.fn_entry = fn_table_entry; | ||
| 1377 | fn_table_entry->proto_node = proto_node; | ||
| 1378 | fn_table_entry->fn_def_node = proto_node->data.fn_proto.fn_def_node; | ||
| 1379 | fn_table_entry->fn_inline = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; | ||
| 1380 | fn_table_entry->internal_linkage = (fn_proto->visib_mod != VisibModExport); | ||
| 1381 | |||
| 1382 | return fn_table_entry; | ||
| 1383 | } | ||
| 1384 | |||
| 1369 | static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | 1385 | static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 1370 | ImportTableEntry *import = tld_fn->base.import; | 1386 | ImportTableEntry *import = tld_fn->base.import; |
| 1371 | AstNode *proto_node = tld_fn->base.source_node; | 1387 | AstNode *proto_node = tld_fn->base.source_node; |
| ... | @@ -1381,17 +1397,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -1381,17 +1397,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 1381 | return; | 1397 | return; |
| 1382 | } | 1398 | } |
| 1383 | 1399 | ||
| 1384 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); | 1400 | FnTableEntry *fn_table_entry = create_fn(g, tld_fn->base.source_node); |
| 1385 | fn_table_entry->analyzed_executable.backward_branch_count = &fn_table_entry->prealloc_bbc; | ||
| 1386 | fn_table_entry->analyzed_executable.backward_branch_quota = default_backward_branch_quota; | ||
| 1387 | fn_table_entry->analyzed_executable.fn_entry = fn_table_entry; | ||
| 1388 | fn_table_entry->ir_executable.fn_entry = fn_table_entry; | ||
| 1389 | fn_table_entry->import_entry = import; | ||
| 1390 | fn_table_entry->proto_node = proto_node; | ||
| 1391 | fn_table_entry->fn_def_node = fn_def_node; | ||
| 1392 | fn_table_entry->fn_inline = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; | ||
| 1393 | fn_table_entry->internal_linkage = (fn_proto->visib_mod != VisibModExport); | ||
| 1394 | |||
| 1395 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); | 1401 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); |
| 1396 | 1402 | ||
| 1397 | tld_fn->fn_entry = fn_table_entry; | 1403 | tld_fn->fn_entry = fn_table_entry; |
| ... | @@ -1399,9 +1405,18 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -1399,9 +1405,18 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 1399 | if (fn_table_entry->fn_def_node) { | 1405 | if (fn_table_entry->fn_def_node) { |
| 1400 | fn_table_entry->fndef_scope = create_fndef_scope( | 1406 | fn_table_entry->fndef_scope = create_fndef_scope( |
| 1401 | fn_table_entry->fn_def_node, tld_fn->base.parent_scope, fn_table_entry); | 1407 | fn_table_entry->fn_def_node, tld_fn->base.parent_scope, fn_table_entry); |
| 1408 | |||
| 1409 | for (size_t i = 0; i < fn_proto->params.length; i += 1) { | ||
| 1410 | AstNode *param_node = fn_proto->params.at(i); | ||
| 1411 | assert(param_node->type == NodeTypeParamDecl); | ||
| 1412 | if (buf_len(param_node->data.param_decl.name) == 0) { | ||
| 1413 | add_node_error(g, param_node, buf_sprintf("missing parameter name")); | ||
| 1414 | } | ||
| 1415 | } | ||
| 1402 | } | 1416 | } |
| 1403 | 1417 | ||
| 1404 | fn_table_entry->type_entry = analyze_fn_type(g, tld_fn); | 1418 | Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; |
| 1419 | fn_table_entry->type_entry = analyze_fn_type(g, proto_node, child_scope); | ||
| 1405 | 1420 | ||
| 1406 | if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) { | 1421 | if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) { |
| 1407 | tld_fn->base.resolution = TldResolutionInvalid; | 1422 | tld_fn->base.resolution = TldResolutionInvalid; |
| ... | @@ -2142,6 +2157,13 @@ bool type_is_codegen_pointer(TypeTableEntry *type) { | ... | @@ -2142,6 +2157,13 @@ bool type_is_codegen_pointer(TypeTableEntry *type) { |
| 2142 | return false; | 2157 | return false; |
| 2143 | } | 2158 | } |
| 2144 | 2159 | ||
| 2160 | AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index) { | ||
| 2161 | if (fn_entry->param_source_nodes) | ||
| 2162 | return fn_entry->param_source_nodes[index]; | ||
| 2163 | else | ||
| 2164 | return fn_entry->proto_node->data.fn_proto.params.at(index); | ||
| 2165 | } | ||
| 2166 | |||
| 2145 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | 2167 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 2146 | assert(fn_table_entry->anal_state != FnAnalStateProbing); | 2168 | assert(fn_table_entry->anal_state != FnAnalStateProbing); |
| 2147 | if (fn_table_entry->anal_state != FnAnalStateReady) | 2169 | if (fn_table_entry->anal_state != FnAnalStateReady) |
| ... | @@ -2151,17 +2173,19 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | ... | @@ -2151,17 +2173,19 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 2151 | 2173 | ||
| 2152 | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; | 2174 | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; |
| 2153 | 2175 | ||
| 2154 | Scope *child_scope = &fn_table_entry->fndef_scope->base; | 2176 | assert(fn_table_entry->fndef_scope); |
| 2155 | assert(child_scope); | 2177 | if (!fn_table_entry->child_scope) |
| 2178 | fn_table_entry->child_scope = &fn_table_entry->fndef_scope->base; | ||
| 2156 | 2179 | ||
| 2157 | // define local variables for parameters | 2180 | // define local variables for parameters |
| 2158 | TypeTableEntry *fn_type = fn_table_entry->type_entry; | 2181 | TypeTableEntry *fn_type = fn_table_entry->type_entry; |
| 2159 | assert(!fn_type->data.fn.is_generic); | 2182 | assert(!fn_type->data.fn.is_generic); |
| 2160 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; | 2183 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| 2161 | for (size_t i = 0; i < fn_type_id->param_count; i += 1) { | 2184 | for (size_t i = 0; i < fn_type_id->param_count; i += 1) { |
| 2162 | AstNode *param_decl_node = fn_proto->params.at(i); | ||
| 2163 | AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl; | ||
| 2164 | FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; | 2185 | FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; |
| 2186 | AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i); | ||
| 2187 | AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl; | ||
| 2188 | |||
| 2165 | 2189 | ||
| 2166 | TypeTableEntry *param_type = param_info->type; | 2190 | TypeTableEntry *param_type = param_info->type; |
| 2167 | bool is_noalias = param_info->is_noalias; | 2191 | bool is_noalias = param_info->is_noalias; |
| ... | @@ -2175,9 +2199,9 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | ... | @@ -2175,9 +2199,9 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 2175 | buf_sprintf("byvalue types not yet supported on extern function parameters")); | 2199 | buf_sprintf("byvalue types not yet supported on extern function parameters")); |
| 2176 | } | 2200 | } |
| 2177 | 2201 | ||
| 2178 | VariableTableEntry *var = add_variable(g, param_decl_node, child_scope, param_decl->name, param_type, true, nullptr); | 2202 | VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, param_decl->name, param_type, true, nullptr); |
| 2179 | var->src_arg_index = i; | 2203 | var->src_arg_index = i; |
| 2180 | child_scope = var->child_scope; | 2204 | fn_table_entry->child_scope = var->child_scope; |
| 2181 | fn_table_entry->variable_list.append(var); | 2205 | fn_table_entry->variable_list.append(var); |
| 2182 | 2206 | ||
| 2183 | if (fn_type->data.fn.gen_param_info) { | 2207 | if (fn_type->data.fn.gen_param_info) { |
| ... | @@ -2185,8 +2209,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | ... | @@ -2185,8 +2209,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 2185 | } | 2209 | } |
| 2186 | } | 2210 | } |
| 2187 | 2211 | ||
| 2188 | fn_table_entry->child_scope = child_scope; | ||
| 2189 | |||
| 2190 | TypeTableEntry *expected_type = fn_type_id->return_type; | 2212 | TypeTableEntry *expected_type = fn_type_id->return_type; |
| 2191 | 2213 | ||
| 2192 | if (fn_type_id->is_extern && handle_is_ptr(expected_type)) { | 2214 | if (fn_type_id->is_extern && handle_is_ptr(expected_type)) { |
| ... | @@ -2622,6 +2644,40 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) | ... | @@ -2622,6 +2644,40 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) |
| 2622 | zig_unreachable(); | 2644 | zig_unreachable(); |
| 2623 | } | 2645 | } |
| 2624 | 2646 | ||
| 2647 | uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { | ||
| 2648 | uint32_t result = 0; | ||
| 2649 | result += hash_ptr(id->fn_entry); | ||
| 2650 | for (size_t i = 0; i < id->param_count; i += 1) { | ||
| 2651 | GenericParamValue *generic_param = &id->params[i]; | ||
| 2652 | if (generic_param->value) { | ||
| 2653 | result += hash_const_val(generic_param->type, generic_param->value); | ||
| 2654 | result += hash_ptr(generic_param->type); | ||
| 2655 | } | ||
| 2656 | } | ||
| 2657 | return result; | ||
| 2658 | } | ||
| 2659 | |||
| 2660 | bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { | ||
| 2661 | assert(a->fn_entry); | ||
| 2662 | if (a->fn_entry != b->fn_entry) return false; | ||
| 2663 | assert(a->param_count == b->param_count); | ||
| 2664 | for (size_t i = 0; i < a->param_count; i += 1) { | ||
| 2665 | GenericParamValue *a_val = &a->params[i]; | ||
| 2666 | GenericParamValue *b_val = &b->params[i]; | ||
| 2667 | if (a_val->type != b_val->type) return false; | ||
| 2668 | if (a_val->value && b_val->value) { | ||
| 2669 | assert(a_val->value->special == ConstValSpecialStatic); | ||
| 2670 | assert(b_val->value->special == ConstValSpecialStatic); | ||
| 2671 | if (!const_values_equal(a_val->value, b_val->value, a_val->type)) { | ||
| 2672 | return false; | ||
| 2673 | } | ||
| 2674 | } else { | ||
| 2675 | assert(!a_val->value && !b_val->value); | ||
| 2676 | } | ||
| 2677 | } | ||
| 2678 | return true; | ||
| 2679 | } | ||
| 2680 | |||
| 2625 | bool type_has_bits(TypeTableEntry *type_entry) { | 2681 | bool type_has_bits(TypeTableEntry *type_entry) { |
| 2626 | assert(type_entry); | 2682 | assert(type_entry); |
| 2627 | assert(type_entry->id != TypeTableEntryIdInvalid); | 2683 | assert(type_entry->id != TypeTableEntryIdInvalid); |
src/analyze.hpp+3| ... | @@ -70,6 +70,9 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source | ... | @@ -70,6 +70,9 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source |
| 70 | VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, | 70 | VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, |
| 71 | TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value); | 71 | TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value); |
| 72 | TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); | 72 | TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); |
| 73 | FnTableEntry *create_fn(CodeGen *g, AstNode *proto_node); | ||
| 74 | void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node); | ||
| 75 | AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index); | ||
| 73 | 76 | ||
| 74 | Scope *create_block_scope(AstNode *node, Scope *parent); | 77 | Scope *create_block_scope(AstNode *node, Scope *parent); |
| 75 | Scope *create_defer_scope(AstNode *node, Scope *parent); | 78 | Scope *create_defer_scope(AstNode *node, Scope *parent); |
src/ast_render.cpp+1-1| ... | @@ -397,7 +397,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -397,7 +397,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 397 | assert(param_decl->type == NodeTypeParamDecl); | 397 | assert(param_decl->type == NodeTypeParamDecl); |
| 398 | if (buf_len(param_decl->data.param_decl.name) > 0) { | 398 | if (buf_len(param_decl->data.param_decl.name) > 0) { |
| 399 | const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : ""; | 399 | const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : ""; |
| 400 | const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : ""; | 400 | const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : ""; |
| 401 | fprintf(ar->f, "%s%s", noalias_str, inline_str); | 401 | fprintf(ar->f, "%s%s", noalias_str, inline_str); |
| 402 | print_symbol(ar, param_decl->data.param_decl.name); | 402 | print_symbol(ar, param_decl->data.param_decl.name); |
| 403 | fprintf(ar->f, ": "); | 403 | fprintf(ar->f, ": "); |
src/codegen.cpp+18-25| ... | @@ -60,6 +60,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { | ... | @@ -60,6 +60,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { |
| 60 | g->primitive_type_table.init(32); | 60 | g->primitive_type_table.init(32); |
| 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->is_release_build = false; | 64 | g->is_release_build = false; |
| 64 | g->is_test_build = false; | 65 | g->is_test_build = false; |
| 65 | g->want_h_file = true; | 66 | g->want_h_file = true; |
| ... | @@ -2305,11 +2306,8 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -2305,11 +2306,8 @@ static void do_code_gen(CodeGen *g) { |
| 2305 | if (should_skip_fn_codegen(g, fn_table_entry)) | 2306 | if (should_skip_fn_codegen(g, fn_table_entry)) |
| 2306 | continue; | 2307 | continue; |
| 2307 | 2308 | ||
| 2308 | AstNode *proto_node = fn_table_entry->proto_node; | ||
| 2309 | assert(proto_node->type == NodeTypeFnProto); | ||
| 2310 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | ||
| 2311 | |||
| 2312 | TypeTableEntry *fn_type = fn_table_entry->type_entry; | 2309 | TypeTableEntry *fn_type = fn_table_entry->type_entry; |
| 2310 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; | ||
| 2313 | 2311 | ||
| 2314 | LLVMValueRef fn_val = fn_llvm_value(g, fn_table_entry); | 2312 | LLVMValueRef fn_val = fn_llvm_value(g, fn_table_entry); |
| 2315 | 2313 | ||
| ... | @@ -2327,22 +2325,20 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -2327,22 +2325,20 @@ static void do_code_gen(CodeGen *g) { |
| 2327 | 2325 | ||
| 2328 | 2326 | ||
| 2329 | // set parameter attributes | 2327 | // set parameter attributes |
| 2330 | for (size_t param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) { | 2328 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { |
| 2331 | AstNode *param_node = fn_proto->params.at(param_decl_i); | 2329 | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; |
| 2332 | assert(param_node->type == NodeTypeParamDecl); | 2330 | size_t gen_index = gen_info->gen_index; |
| 2333 | 2331 | bool is_byval = gen_info->is_byval; | |
| 2334 | FnGenParamInfo *info = &fn_type->data.fn.gen_param_info[param_decl_i]; | ||
| 2335 | size_t gen_index = info->gen_index; | ||
| 2336 | bool is_byval = info->is_byval; | ||
| 2337 | 2332 | ||
| 2338 | if (gen_index == SIZE_MAX) { | 2333 | if (gen_index == SIZE_MAX) { |
| 2339 | continue; | 2334 | continue; |
| 2340 | } | 2335 | } |
| 2341 | 2336 | ||
| 2342 | TypeTableEntry *param_type = info->type; | 2337 | FnTypeParamInfo *param_info = &fn_type_id->param_info[param_i]; |
| 2338 | |||
| 2339 | TypeTableEntry *param_type = gen_info->type; | ||
| 2343 | LLVMValueRef argument_val = LLVMGetParam(fn_val, gen_index); | 2340 | LLVMValueRef argument_val = LLVMGetParam(fn_val, gen_index); |
| 2344 | bool param_is_noalias = param_node->data.param_decl.is_noalias; | 2341 | if (param_info->is_noalias) { |
| 2345 | if (param_is_noalias) { | ||
| 2346 | LLVMAddAttribute(argument_val, LLVMNoAliasAttribute); | 2342 | LLVMAddAttribute(argument_val, LLVMNoAliasAttribute); |
| 2347 | } | 2343 | } |
| 2348 | if ((param_type->id == TypeTableEntryIdPointer && param_type->data.pointer.is_const) || is_byval) { | 2344 | if ((param_type->id == TypeTableEntryIdPointer && param_type->data.pointer.is_const) || is_byval) { |
| ... | @@ -2402,7 +2398,6 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -2402,7 +2398,6 @@ static void do_code_gen(CodeGen *g) { |
| 2402 | if (should_skip_fn_codegen(g, fn_table_entry)) | 2398 | if (should_skip_fn_codegen(g, fn_table_entry)) |
| 2403 | continue; | 2399 | continue; |
| 2404 | 2400 | ||
| 2405 | ImportTableEntry *import = fn_table_entry->import_entry; | ||
| 2406 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); | 2401 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); |
| 2407 | g->cur_fn = fn_table_entry; | 2402 | g->cur_fn = fn_table_entry; |
| 2408 | g->cur_fn_val = fn; | 2403 | g->cur_fn_val = fn; |
| ... | @@ -2412,10 +2407,6 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -2412,10 +2407,6 @@ static void do_code_gen(CodeGen *g) { |
| 2412 | g->cur_ret_ptr = nullptr; | 2407 | g->cur_ret_ptr = nullptr; |
| 2413 | } | 2408 | } |
| 2414 | 2409 | ||
| 2415 | AstNode *proto_node = fn_table_entry->proto_node; | ||
| 2416 | assert(proto_node->type == NodeTypeFnProto); | ||
| 2417 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | ||
| 2418 | |||
| 2419 | build_all_basic_blocks(g, fn_table_entry); | 2410 | build_all_basic_blocks(g, fn_table_entry); |
| 2420 | clear_debug_source_node(g); | 2411 | clear_debug_source_node(g); |
| 2421 | 2412 | ||
| ... | @@ -2444,6 +2435,8 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -2444,6 +2435,8 @@ static void do_code_gen(CodeGen *g) { |
| 2444 | *slot = LLVMBuildAlloca(g->builder, instruction->type_entry->type_ref, ""); | 2435 | *slot = LLVMBuildAlloca(g->builder, instruction->type_entry->type_ref, ""); |
| 2445 | } | 2436 | } |
| 2446 | 2437 | ||
| 2438 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); | ||
| 2439 | |||
| 2447 | // create debug variable declarations for variables and allocate all local variables | 2440 | // create debug variable declarations for variables and allocate all local variables |
| 2448 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { | 2441 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { |
| 2449 | VariableTableEntry *var = fn_table_entry->variable_list.at(var_i); | 2442 | VariableTableEntry *var = fn_table_entry->variable_list.at(var_i); |
| ... | @@ -2484,10 +2477,12 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -2484,10 +2477,12 @@ static void do_code_gen(CodeGen *g) { |
| 2484 | } | 2477 | } |
| 2485 | } | 2478 | } |
| 2486 | 2479 | ||
| 2480 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; | ||
| 2481 | |||
| 2487 | // create debug variable declarations for parameters | 2482 | // create debug variable declarations for parameters |
| 2488 | // rely on the first variables in the variable_list being parameters. | 2483 | // rely on the first variables in the variable_list being parameters. |
| 2489 | size_t next_var_i = 0; | 2484 | size_t next_var_i = 0; |
| 2490 | for (size_t param_i = 0; param_i < fn_proto->params.length; param_i += 1) { | 2485 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { |
| 2491 | FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i]; | 2486 | FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i]; |
| 2492 | if (info->gen_index == SIZE_MAX) | 2487 | if (info->gen_index == SIZE_MAX) |
| 2493 | continue; | 2488 | continue; |
| ... | @@ -3392,14 +3387,12 @@ void codegen_generate_h_file(CodeGen *g) { | ... | @@ -3392,14 +3387,12 @@ void codegen_generate_h_file(CodeGen *g) { |
| 3392 | buf_resize(&h_buf, 0); | 3387 | buf_resize(&h_buf, 0); |
| 3393 | for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { | 3388 | for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { |
| 3394 | FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i); | 3389 | FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i); |
| 3395 | AstNode *proto_node = fn_table_entry->proto_node; | ||
| 3396 | assert(proto_node->type == NodeTypeFnProto); | ||
| 3397 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | ||
| 3398 | 3390 | ||
| 3399 | if (fn_proto->visib_mod != VisibModExport) | 3391 | if (fn_table_entry->internal_linkage) |
| 3400 | continue; | 3392 | continue; |
| 3401 | 3393 | ||
| 3402 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; | 3394 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; |
| 3395 | |||
| 3403 | Buf return_type_c = BUF_INIT; | 3396 | Buf return_type_c = BUF_INIT; |
| 3404 | get_c_type(g, fn_type_id->return_type, &return_type_c); | 3397 | get_c_type(g, fn_type_id->return_type, &return_type_c); |
| 3405 | 3398 | ||
| ... | @@ -3412,7 +3405,7 @@ void codegen_generate_h_file(CodeGen *g) { | ... | @@ -3412,7 +3405,7 @@ void codegen_generate_h_file(CodeGen *g) { |
| 3412 | if (fn_type_id->param_count > 0) { | 3405 | if (fn_type_id->param_count > 0) { |
| 3413 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { | 3406 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { |
| 3414 | FnTypeParamInfo *param_info = &fn_type_id->param_info[param_i]; | 3407 | FnTypeParamInfo *param_info = &fn_type_id->param_info[param_i]; |
| 3415 | AstNode *param_decl_node = fn_proto->params.at(param_i); | 3408 | AstNode *param_decl_node = get_param_decl_node(fn_table_entry, param_i); |
| 3416 | Buf *param_name = param_decl_node->data.param_decl.name; | 3409 | Buf *param_name = param_decl_node->data.param_decl.name; |
| 3417 | 3410 | ||
| 3418 | const char *comma_str = (param_i == 0) ? "" : ", "; | 3411 | const char *comma_str = (param_i == 0) ? "" : ", "; |
src/ir.cpp+143-11| ... | @@ -2825,9 +2825,8 @@ IrInstruction *ir_gen_fn(CodeGen *codegen, FnTableEntry *fn_entry) { | ... | @@ -2825,9 +2825,8 @@ IrInstruction *ir_gen_fn(CodeGen *codegen, FnTableEntry *fn_entry) { |
| 2825 | AstNode *body_node = fn_def_node->data.fn_def.body; | 2825 | AstNode *body_node = fn_def_node->data.fn_def.body; |
| 2826 | 2826 | ||
| 2827 | assert(fn_entry->child_scope); | 2827 | assert(fn_entry->child_scope); |
| 2828 | Scope *child_scope = fn_entry->child_scope; | ||
| 2829 | 2828 | ||
| 2830 | return ir_gen(codegen, body_node, child_scope, ir_executable); | 2829 | return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable); |
| 2831 | } | 2830 | } |
| 2832 | 2831 | ||
| 2833 | static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, Buf *msg) { | 2832 | static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, Buf *msg) { |
| ... | @@ -4220,9 +4219,9 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc | ... | @@ -4220,9 +4219,9 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc |
| 4220 | } | 4219 | } |
| 4221 | 4220 | ||
| 4222 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, | 4221 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| 4223 | IrInstruction *arg, Scope **exec_scope, size_t *next_arg_index) | 4222 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) |
| 4224 | { | 4223 | { |
| 4225 | AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_arg_index); | 4224 | AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i); |
| 4226 | assert(param_decl_node->type == NodeTypeParamDecl); | 4225 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 4227 | AstNode *param_type_node = param_decl_node->data.param_decl.type; | 4226 | AstNode *param_type_node = param_decl_node->data.param_decl.type; |
| 4228 | TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *exec_scope, param_type_node); | 4227 | TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *exec_scope, param_type_node); |
| ... | @@ -4241,14 +4240,66 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node | ... | @@ -4241,14 +4240,66 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node |
| 4241 | VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, | 4240 | VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, |
| 4242 | *exec_scope, param_name, param_type, true, first_arg_val); | 4241 | *exec_scope, param_name, param_type, true, first_arg_val); |
| 4243 | *exec_scope = var->child_scope; | 4242 | *exec_scope = var->child_scope; |
| 4244 | *next_arg_index += 1; | 4243 | *next_proto_i += 1; |
| 4245 | 4244 | ||
| 4246 | return true; | 4245 | return true; |
| 4247 | } | 4246 | } |
| 4248 | 4247 | ||
| 4248 | static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_node, | ||
| 4249 | IrInstruction *arg, Scope **child_scope, size_t *next_proto_i, | ||
| 4250 | GenericFnTypeId *generic_id, FnTypeId *fn_type_id, IrInstruction **casted_args, | ||
| 4251 | FnTableEntry *impl_fn) | ||
| 4252 | { | ||
| 4253 | AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i); | ||
| 4254 | assert(param_decl_node->type == NodeTypeParamDecl); | ||
| 4255 | AstNode *param_type_node = param_decl_node->data.param_decl.type; | ||
| 4256 | TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node); | ||
| 4257 | if (param_type->id == TypeTableEntryIdInvalid) | ||
| 4258 | return false; | ||
| 4259 | |||
| 4260 | bool is_var_type = (param_type->id == TypeTableEntryIdVar); | ||
| 4261 | IrInstruction *casted_arg; | ||
| 4262 | if (is_var_type) { | ||
| 4263 | casted_arg = arg; | ||
| 4264 | } else { | ||
| 4265 | casted_arg = ir_get_casted_value(ira, arg, param_type); | ||
| 4266 | if (casted_arg->type_entry->id == TypeTableEntryIdInvalid) | ||
| 4267 | return false; | ||
| 4268 | } | ||
| 4269 | |||
| 4270 | bool inline_arg = param_decl_node->data.param_decl.is_inline; | ||
| 4271 | if (inline_arg || is_var_type) { | ||
| 4272 | ConstExprValue *arg_val = ir_resolve_const(ira, casted_arg); | ||
| 4273 | if (!arg_val) | ||
| 4274 | return false; | ||
| 4275 | |||
| 4276 | Buf *param_name = param_decl_node->data.param_decl.name; | ||
| 4277 | VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, | ||
| 4278 | *child_scope, param_name, param_type, true, arg_val); | ||
| 4279 | *child_scope = var->child_scope; | ||
| 4280 | // This generic function instance could be called with anything, so when this variable is read it | ||
| 4281 | // needs to know that it depends on compile time variable data. | ||
| 4282 | var->value->depends_on_compile_var = true; | ||
| 4283 | |||
| 4284 | GenericParamValue *generic_param = &generic_id->params[generic_id->param_count]; | ||
| 4285 | generic_param->type = casted_arg->type_entry; | ||
| 4286 | generic_param->value = arg_val; | ||
| 4287 | generic_id->param_count += 1; | ||
| 4288 | } else { | ||
| 4289 | casted_args[fn_type_id->param_count] = casted_arg; | ||
| 4290 | FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count]; | ||
| 4291 | param_info->type = param_type; | ||
| 4292 | param_info->is_noalias = param_decl_node->data.param_decl.is_noalias; | ||
| 4293 | impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node; | ||
| 4294 | fn_type_id->param_count += 1; | ||
| 4295 | } | ||
| 4296 | *next_proto_i += 1; | ||
| 4297 | return true; | ||
| 4298 | } | ||
| 4299 | |||
| 4249 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, | 4300 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, |
| 4250 | FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref, | 4301 | FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref, |
| 4251 | IrInstruction *first_arg_ptr, bool is_inline) | 4302 | IrInstruction *first_arg_ptr, bool inline_fn_call) |
| 4252 | { | 4303 | { |
| 4253 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; | 4304 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| 4254 | size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; | 4305 | size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; |
| ... | @@ -4278,7 +4329,8 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -4278,7 +4329,8 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 4278 | return ira->codegen->builtin_types.entry_invalid; | 4329 | return ira->codegen->builtin_types.entry_invalid; |
| 4279 | } | 4330 | } |
| 4280 | 4331 | ||
| 4281 | if (is_inline) { | 4332 | if (inline_fn_call) { |
| 4333 | // No special handling is needed for compile time evaluation of generic functions. | ||
| 4282 | if (!fn_entry) { | 4334 | if (!fn_entry) { |
| 4283 | ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression")); | 4335 | ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression")); |
| 4284 | return ira->codegen->builtin_types.entry_invalid; | 4336 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -4290,13 +4342,13 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -4290,13 +4342,13 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 4290 | // Fork a scope of the function with known values for the parameters. | 4342 | // Fork a scope of the function with known values for the parameters. |
| 4291 | Scope *exec_scope = &fn_entry->fndef_scope->base; | 4343 | Scope *exec_scope = &fn_entry->fndef_scope->base; |
| 4292 | 4344 | ||
| 4293 | size_t next_arg_index = 0; | 4345 | size_t next_proto_i = 0; |
| 4294 | if (first_arg_ptr) { | 4346 | if (first_arg_ptr) { |
| 4295 | IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); | 4347 | IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); |
| 4296 | if (first_arg->type_entry->id == TypeTableEntryIdInvalid) | 4348 | if (first_arg->type_entry->id == TypeTableEntryIdInvalid) |
| 4297 | return ira->codegen->builtin_types.entry_invalid; | 4349 | return ira->codegen->builtin_types.entry_invalid; |
| 4298 | 4350 | ||
| 4299 | if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, first_arg, &exec_scope, &next_arg_index)) | 4351 | if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, first_arg, &exec_scope, &next_proto_i)) |
| 4300 | return ira->codegen->builtin_types.entry_invalid; | 4352 | return ira->codegen->builtin_types.entry_invalid; |
| 4301 | } | 4353 | } |
| 4302 | 4354 | ||
| ... | @@ -4305,7 +4357,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -4305,7 +4357,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 4305 | if (old_arg->type_entry->id == TypeTableEntryIdInvalid) | 4357 | if (old_arg->type_entry->id == TypeTableEntryIdInvalid) |
| 4306 | return ira->codegen->builtin_types.entry_invalid; | 4358 | return ira->codegen->builtin_types.entry_invalid; |
| 4307 | 4359 | ||
| 4308 | if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, old_arg, &exec_scope, &next_arg_index)) | 4360 | if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, old_arg, &exec_scope, &next_proto_i)) |
| 4309 | return ira->codegen->builtin_types.entry_invalid; | 4361 | return ira->codegen->builtin_types.entry_invalid; |
| 4310 | } | 4362 | } |
| 4311 | 4363 | ||
| ... | @@ -4327,9 +4379,89 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -4327,9 +4379,89 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 4327 | return ir_finish_anal(ira, return_type); | 4379 | return ir_finish_anal(ira, return_type); |
| 4328 | } | 4380 | } |
| 4329 | 4381 | ||
| 4382 | if (fn_type->data.fn.is_generic) { | ||
| 4383 | assert(fn_entry); | ||
| 4384 | |||
| 4385 | IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count); | ||
| 4386 | |||
| 4387 | // Fork a scope of the function with known values for the parameters. | ||
| 4388 | Scope *parent_scope = fn_entry->fndef_scope->base.parent; | ||
| 4389 | FnTableEntry *impl_fn = create_fn(ira->codegen, fn_proto_node); | ||
| 4390 | impl_fn->param_source_nodes = allocate<AstNode *>(call_param_count); | ||
| 4391 | buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name); | ||
| 4392 | impl_fn->fndef_scope = create_fndef_scope(impl_fn->fn_def_node, parent_scope, impl_fn); | ||
| 4393 | impl_fn->child_scope = &impl_fn->fndef_scope->base; | ||
| 4394 | FnTypeId fn_type_id = {0}; | ||
| 4395 | init_fn_type_id(&fn_type_id, fn_proto_node); | ||
| 4396 | fn_type_id.param_count = 0; | ||
| 4397 | |||
| 4398 | // TODO maybe GenericFnTypeId can be replaced with using the child_scope directly | ||
| 4399 | // as the key in generic_table | ||
| 4400 | GenericFnTypeId *generic_id = allocate<GenericFnTypeId>(1); | ||
| 4401 | generic_id->fn_entry = fn_entry; | ||
| 4402 | generic_id->param_count = 0; | ||
| 4403 | generic_id->params = allocate<GenericParamValue>(src_param_count); | ||
| 4404 | size_t next_proto_i = 0; | ||
| 4405 | |||
| 4406 | if (first_arg_ptr) { | ||
| 4407 | IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); | ||
| 4408 | if (first_arg->type_entry->id == TypeTableEntryIdInvalid) | ||
| 4409 | return ira->codegen->builtin_types.entry_invalid; | ||
| 4410 | |||
| 4411 | if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, first_arg, &impl_fn->child_scope, | ||
| 4412 | &next_proto_i, generic_id, &fn_type_id, casted_args, impl_fn)) | ||
| 4413 | { | ||
| 4414 | return ira->codegen->builtin_types.entry_invalid; | ||
| 4415 | } | ||
| 4416 | } | ||
| 4417 | for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) { | ||
| 4418 | IrInstruction *arg = call_instruction->args[call_i]->other; | ||
| 4419 | if (arg->type_entry->id == TypeTableEntryIdInvalid) | ||
| 4420 | return ira->codegen->builtin_types.entry_invalid; | ||
| 4421 | |||
| 4422 | if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope, | ||
| 4423 | &next_proto_i, generic_id, &fn_type_id, casted_args, impl_fn)) | ||
| 4424 | { | ||
| 4425 | return ira->codegen->builtin_types.entry_invalid; | ||
| 4426 | } | ||
| 4427 | } | ||
| 4428 | |||
| 4429 | auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn); | ||
| 4430 | if (existing_entry) { | ||
| 4431 | // throw away all our work and use the existing function | ||
| 4432 | impl_fn = existing_entry->value; | ||
| 4433 | } else { | ||
| 4434 | // finish instantiating the function | ||
| 4435 | AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; | ||
| 4436 | TypeTableEntry *return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node); | ||
| 4437 | if (return_type->id == TypeTableEntryIdInvalid) | ||
| 4438 | return ira->codegen->builtin_types.entry_invalid; | ||
| 4439 | fn_type_id.return_type = return_type; | ||
| 4440 | |||
| 4441 | impl_fn->type_entry = get_fn_type(ira->codegen, &fn_type_id); | ||
| 4442 | if (impl_fn->type_entry->id == TypeTableEntryIdInvalid) | ||
| 4443 | return ira->codegen->builtin_types.entry_invalid; | ||
| 4444 | |||
| 4445 | ira->codegen->fn_protos.append(impl_fn); | ||
| 4446 | ira->codegen->fn_defs.append(impl_fn); | ||
| 4447 | } | ||
| 4448 | |||
| 4449 | size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; | ||
| 4450 | IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, | ||
| 4451 | impl_fn, nullptr, impl_param_count, casted_args); | ||
| 4452 | |||
| 4453 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; | ||
| 4454 | if (type_has_bits(return_type) && handle_is_ptr(return_type)) { | ||
| 4455 | FnTableEntry *callsite_fn = exec_fn_entry(ira->new_irb.exec); | ||
| 4456 | assert(callsite_fn); | ||
| 4457 | callsite_fn->alloca_list.append(new_call_instruction); | ||
| 4458 | } | ||
| 4459 | |||
| 4460 | return ir_finish_anal(ira, return_type); | ||
| 4461 | } | ||
| 4462 | |||
| 4330 | IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count); | 4463 | IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count); |
| 4331 | size_t next_arg_index = 0; | 4464 | size_t next_arg_index = 0; |
| 4332 | |||
| 4333 | if (first_arg_ptr) { | 4465 | if (first_arg_ptr) { |
| 4334 | IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); | 4466 | IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); |
| 4335 | if (first_arg->type_entry->id == TypeTableEntryIdInvalid) | 4467 | if (first_arg->type_entry->id == TypeTableEntryIdInvalid) |
test/self_hosted2.zig+29| ... | @@ -111,6 +111,33 @@ fn testCompileTimeFib() { | ... | @@ -111,6 +111,33 @@ fn testCompileTimeFib() { |
| 111 | assert(fib_7 == 13); | 111 | assert(fib_7 == 13); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | fn max(inline T: type, a: T, b: T) -> T { | ||
| 115 | if (a > b) a else b | ||
| 116 | } | ||
| 117 | const the_max = max(u32, 1234, 5678); | ||
| 118 | |||
| 119 | fn testCompileTimeGenericEval() { | ||
| 120 | assert(the_max == 5678); | ||
| 121 | } | ||
| 122 | |||
| 123 | fn gimmeTheBigOne(a: u32, b: u32) -> u32 { | ||
| 124 | max(u32, a, b) | ||
| 125 | } | ||
| 126 | |||
| 127 | fn shouldCallSameInstance(a: u32, b: u32) -> u32 { | ||
| 128 | max(u32, a, b) | ||
| 129 | } | ||
| 130 | |||
| 131 | fn sameButWithFloats(a: f64, b: f64) -> f64 { | ||
| 132 | max(f64, a, b) | ||
| 133 | } | ||
| 134 | |||
| 135 | fn testFnWithInlineArgs() { | ||
| 136 | assert(gimmeTheBigOne(1234, 5678) == 5678); | ||
| 137 | assert(shouldCallSameInstance(34, 12) == 34); | ||
| 138 | assert(sameButWithFloats(0.43, 0.49) == 0.49); | ||
| 139 | } | ||
| 140 | |||
| 114 | 141 | ||
| 115 | fn assert(ok: bool) { | 142 | fn assert(ok: bool) { |
| 116 | if (!ok) | 143 | if (!ok) |
| ... | @@ -129,6 +156,8 @@ fn runAllTests() { | ... | @@ -129,6 +156,8 @@ fn runAllTests() { |
| 129 | testStructStatic(); | 156 | testStructStatic(); |
| 130 | testStaticFnEval(); | 157 | testStaticFnEval(); |
| 131 | testCompileTimeFib(); | 158 | testCompileTimeFib(); |
| 159 | testCompileTimeGenericEval(); | ||
| 160 | testFnWithInlineArgs(); | ||
| 132 | } | 161 | } |
| 133 | 162 | ||
| 134 | export nakedcc fn _start() -> unreachable { | 163 | export nakedcc fn _start() -> unreachable { |