authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-05 05:12:05-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-05 05:12:44-05:00
log0541532ed6cf5a32b57a4a3f74e6d3a1699223a7
tree3359c1bc68ea224c55e9d2ffb5261eff6f7c2b9f
parent363606d87b3f45c7f62969f85062e2a7b1b4b5dc

IR: implement generic function calls


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};
728728
729struct GenericParamValue {
730 TypeTableEntry *type;
731 ConstExprValue *value;
732};
733
734struct GenericFnTypeId {
735 FnTableEntry *fn_entry;
736 GenericParamValue *params;
737 size_t param_count;
738};
739
740uint32_t generic_fn_type_id_hash(GenericFnTypeId *id);
741bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b);
729742
730struct FnTypeId {743struct 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 decls970 ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls
958 Scope *child_scope; // parent is scope for last parameter971 Scope *child_scope; // parent is scope for last parameter
959 ScopeBlock *def_scope; // parent is child_scope972 ScopeBlock *def_scope; // parent is child_scope
960 ImportTableEntry *import_entry;
961 Buf symbol_name;973 Buf symbol_name;
962 TypeTableEntry *type_entry; // function type974 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;
972985
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;
10531067
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}
909909
910static TypeTableEntry *analyze_fn_type(CodeGen *g, TldFn *tld_fn) {910void 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;
914913
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}
923922
924 FnTableEntry *fn_entry = tld_fn->fn_entry;923static 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);
926929
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 }
941944
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);
947946
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}
13681367
1368FnTableEntry *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
1369static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {1385static 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 }
13831399
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, '_');
13961402
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 }
14031417
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);
14051420
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}
21442159
2160AstNode *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
2145static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {2167static 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) {
21512173
2152 AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;2174 AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;
21532175
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;
21562179
2157 // define local variables for parameters2180 // 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
21652189
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 }
21772201
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);
21822206
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 }
21872211
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;
21912213
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}
26242646
2647uint32_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
2660bool 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
2625bool type_has_bits(TypeTableEntry *type_entry) {2681bool 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
70VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,70VariableTableEntry *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);
72TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);72TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);
73FnTableEntry *create_fn(CodeGen *g, AstNode *proto_node);
74void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node);
75AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index);
7376
74Scope *create_block_scope(AstNode *node, Scope *parent);77Scope *create_block_scope(AstNode *node, Scope *parent);
75Scope *create_defer_scope(AstNode *node, Scope *parent);78Scope *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;
23072308
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;
23132311
2314 LLVMValueRef fn_val = fn_llvm_value(g, fn_table_entry);2312 LLVMValueRef fn_val = fn_llvm_value(g, fn_table_entry);
23152313
...@@ -2327,22 +2325,20 @@ static void do_code_gen(CodeGen *g) {...@@ -2327,22 +2325,20 @@ static void do_code_gen(CodeGen *g) {
23272325
23282326
2329 // set parameter attributes2327 // 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;
23332331 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;
23372332
2338 if (gen_index == SIZE_MAX) {2333 if (gen_index == SIZE_MAX) {
2339 continue;2334 continue;
2340 }2335 }
23412336
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;
24042400
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 }
24142409
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);
24212412
...@@ -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 }
24462437
2438 ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
2439
2447 // create debug variable declarations for variables and allocate all local variables2440 // 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 }
24862479
2480 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
2481
2487 // create debug variable declarations for parameters2482 // 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;
33983390
3399 if (fn_proto->visib_mod != VisibModExport)3391 if (fn_table_entry->internal_linkage)
3400 continue;3392 continue;
34013393
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);
34053398
...@@ -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;
34173410
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;
28262826
2827 assert(fn_entry->child_scope);2827 assert(fn_entry->child_scope);
2828 Scope *child_scope = fn_entry->child_scope;
28292828
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}
28322831
2833static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, Buf *msg) {2832static 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}
42214220
4222static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,4221static 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;
42454244
4246 return true;4245 return true;
4247}4246}
42484247
4248static 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
4249static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,4300static 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 }
42804331
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;
42924344
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;
42984350
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 }
43024354
...@@ -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;
43074359
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 }
43114363
...@@ -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 }
43294381
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}
113113
114fn max(inline T: type, a: T, b: T) -> T {
115 if (a > b) a else b
116}
117const the_max = max(u32, 1234, 5678);
118
119fn testCompileTimeGenericEval() {
120 assert(the_max == 5678);
121}
122
123fn gimmeTheBigOne(a: u32, b: u32) -> u32 {
124 max(u32, a, b)
125}
126
127fn shouldCallSameInstance(a: u32, b: u32) -> u32 {
128 max(u32, a, b)
129}
130
131fn sameButWithFloats(a: f64, b: f64) -> f64 {
132 max(f64, a, b)
133}
134
135fn testFnWithInlineArgs() {
136 assert(gimmeTheBigOne(1234, 5678) == 5678);
137 assert(shouldCallSameInstance(34, 12) == 34);
138 assert(sameButWithFloats(0.43, 0.49) == 0.49);
139}
140
114141
115fn assert(ok: bool) {142fn 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}
133162
134export nakedcc fn _start() -> unreachable {163export nakedcc fn _start() -> unreachable {