authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-18 16:42:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-18 16:42:45-07:00
log32821e7098ba29c30e458f555f62954ce54dcb1a
treeefc8326896f255c9ba6f12e28c4e83612242271c
parent3a326d50051ad8b65639e5e2bbe45e41a8b35591

add function pointer support

See #14

7 files changed, 136 insertions(+), 97 deletions(-)

src/all_types.hpp+11-6
...@@ -566,6 +566,7 @@ struct AstNodeSymbolExpr {...@@ -566,6 +566,7 @@ struct AstNodeSymbolExpr {
566 // populated by semantic analyzer566 // populated by semantic analyzer
567 Expr resolved_expr;567 Expr resolved_expr;
568 VariableTableEntry *variable;568 VariableTableEntry *variable;
569 FnTableEntry *fn_entry;
569};570};
570571
571struct AstNodeBoolLiteral {572struct AstNodeBoolLiteral {
...@@ -720,7 +721,12 @@ struct TypeTableEntryEnum {...@@ -720,7 +721,12 @@ struct TypeTableEntryEnum {
720struct TypeTableEntryFn {721struct TypeTableEntryFn {
721 TypeTableEntry *return_type;722 TypeTableEntry *return_type;
722 TypeTableEntry **param_types;723 TypeTableEntry **param_types;
723 int param_count;724 int src_param_count;
725 LLVMTypeRef raw_type_ref;
726 bool is_var_args;
727 int gen_param_count;
728 LLVMCallConv calling_convention;
729 bool is_naked;
724};730};
725731
726enum TypeTableEntryId {732enum TypeTableEntryId {
...@@ -784,6 +790,7 @@ struct ImportTableEntry {...@@ -784,6 +790,7 @@ struct ImportTableEntry {
784790
785 // reminder: hash tables must be initialized before use791 // reminder: hash tables must be initialized before use
786 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;792 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
793 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> fn_type_table;
787};794};
788795
789struct LabelTableEntry {796struct LabelTableEntry {
...@@ -797,17 +804,15 @@ struct FnTableEntry {...@@ -797,17 +804,15 @@ struct FnTableEntry {
797 LLVMValueRef fn_value;804 LLVMValueRef fn_value;
798 AstNode *proto_node;805 AstNode *proto_node;
799 AstNode *fn_def_node;806 AstNode *fn_def_node;
800 bool is_extern;
801 bool internal_linkage;
802 unsigned calling_convention;
803 ImportTableEntry *import_entry;807 ImportTableEntry *import_entry;
804 bool is_naked;
805 bool is_inline;
806 // Required to be a pre-order traversal of the AST. (parents must come before children)808 // Required to be a pre-order traversal of the AST. (parents must come before children)
807 ZigList<BlockContext *> all_block_contexts;809 ZigList<BlockContext *> all_block_contexts;
808 TypeTableEntry *member_of_struct;810 TypeTableEntry *member_of_struct;
809 Buf symbol_name;811 Buf symbol_name;
810 TypeTableEntry *type_entry; // function type812 TypeTableEntry *type_entry; // function type
813 bool is_inline;
814 bool internal_linkage;
815 bool is_extern;
811816
812 // reminder: hash tables must be initialized before use817 // reminder: hash tables must be initialized before use
813 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;818 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
src/analyze.cpp+56-28
...@@ -348,6 +348,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -348,6 +348,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
348 assert(node->type == NodeTypeFnProto);348 assert(node->type == NodeTypeFnProto);
349 AstNodeFnProto *fn_proto = &node->data.fn_proto;349 AstNodeFnProto *fn_proto = &node->data.fn_proto;
350350
351 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
352 fn_type->data.fn.calling_convention = fn_table_entry->internal_linkage ? LLVMFastCallConv : LLVMCCallConv;
353
351 for (int i = 0; i < fn_proto->directives->length; i += 1) {354 for (int i = 0; i < fn_proto->directives->length; i += 1) {
352 AstNode *directive_node = fn_proto->directives->at(i);355 AstNode *directive_node = fn_proto->directives->at(i);
353 Buf *name = &directive_node->data.directive.name;356 Buf *name = &directive_node->data.directive.name;
...@@ -356,7 +359,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -356,7 +359,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
356 Buf *attr_name = &directive_node->data.directive.param;359 Buf *attr_name = &directive_node->data.directive.param;
357 if (fn_table_entry->fn_def_node) {360 if (fn_table_entry->fn_def_node) {
358 if (buf_eql_str(attr_name, "naked")) {361 if (buf_eql_str(attr_name, "naked")) {
359 fn_table_entry->is_naked = true;362 fn_type->data.fn.is_naked = true;
360 } else if (buf_eql_str(attr_name, "inline")) {363 } else if (buf_eql_str(attr_name, "inline")) {
361 fn_table_entry->is_inline = true;364 fn_table_entry->is_inline = true;
362 } else {365 } else {
...@@ -373,20 +376,24 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -373,20 +376,24 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
373 }376 }
374 }377 }
375378
376 int param_count = node->data.fn_proto.params.length;379 int src_param_count = node->data.fn_proto.params.length;
377380
378 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);381 fn_type->size_in_bits = g->pointer_size_bytes * 8;
379 fn_type->data.fn.param_count = param_count;382 fn_type->align_in_bits = g->pointer_size_bytes * 8;
380 fn_type->data.fn.param_types = allocate<TypeTableEntry*>(param_count);383 fn_type->data.fn.src_param_count = src_param_count;
384 fn_type->data.fn.param_types = allocate<TypeTableEntry*>(src_param_count);
381385
382 fn_table_entry->type_entry = fn_type;386 fn_table_entry->type_entry = fn_type;
383387
384 buf_resize(&fn_type->name, 0);388 buf_resize(&fn_type->name, 0);
385 buf_appendf(&fn_type->name, "fn(");389 const char *export_str = fn_table_entry->internal_linkage ? "" : "export ";
390 const char *inline_str = fn_table_entry->is_inline ? "inline " : "";
391 const char *naked_str = fn_type->data.fn.is_naked ? "naked " : "";
392 buf_appendf(&fn_type->name, "%s%s%sfn(", export_str, inline_str, naked_str);
386 int gen_param_count = 0;393 int gen_param_count = 0;
387 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(param_count);394 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(src_param_count);
388 LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(1 + param_count);395 LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(1 + src_param_count);
389 for (int i = 0; i < param_count; i += 1) {396 for (int i = 0; i < src_param_count; i += 1) {
390 AstNode *child = node->data.fn_proto.params.at(i);397 AstNode *child = node->data.fn_proto.params.at(i);
391 assert(child->type == NodeTypeParamDecl);398 assert(child->type == NodeTypeParamDecl);
392 TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,399 TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,
...@@ -416,6 +423,13 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -416,6 +423,13 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
416 }423 }
417 }424 }
418425
426 fn_type->data.fn.gen_param_count = gen_param_count;
427 fn_type->data.fn.is_var_args = fn_proto->is_var_args;
428 if (fn_proto->is_var_args) {
429 const char *comma = (gen_param_count == 0) ? "" : ", ";
430 buf_appendf(&fn_type->name, "%s...", comma);
431 }
432
419 TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context,433 TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context,
420 node->data.fn_proto.return_type);434 node->data.fn_proto.return_type);
421 fn_type->data.fn.return_type = return_type;435 fn_type->data.fn.return_type = return_type;
...@@ -432,16 +446,29 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -432,16 +446,29 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
432 return;446 return;
433 }447 }
434448
435 fn_type->type_ref = LLVMFunctionType(return_type->type_ref, gen_param_types, gen_param_count,449 auto table_entry = import->fn_type_table.maybe_get(&fn_type->name);
436 fn_proto->is_var_args);450 if (table_entry) {
451 fn_type = table_entry->value;
452 fn_table_entry->type_entry = fn_type;
453 } else {
454 fn_type->data.fn.raw_type_ref = LLVMFunctionType(return_type->type_ref, gen_param_types, gen_param_count,
455 fn_type->data.fn.is_var_args);
456 fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
457 param_di_types[0] = return_type->di_type;
458 fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, import->di_file,
459 param_di_types, gen_param_count + 1, 0);
460
461 import->fn_type_table.put(&fn_type->name, fn_type);
462 }
463
437464
438 fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(&fn_table_entry->symbol_name),465 fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(&fn_table_entry->symbol_name),
439 fn_table_entry->type_entry->type_ref);466 fn_type->data.fn.raw_type_ref);
440467
441 if (fn_table_entry->is_inline) {468 if (fn_table_entry->is_inline) {
442 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute);469 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute);
443 }470 }
444 if (fn_table_entry->is_naked) {471 if (fn_type->data.fn.is_naked) {
445 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute);472 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute);
446 }473 }
447474
...@@ -451,15 +478,11 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -451,15 +478,11 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
451 if (return_type->id == TypeTableEntryIdUnreachable) {478 if (return_type->id == TypeTableEntryIdUnreachable) {
452 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);479 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
453 }480 }
454 LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_table_entry->calling_convention);481 LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);
455 if (!fn_table_entry->is_extern) {482 if (!fn_table_entry->is_extern) {
456 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute);483 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute);
457 }484 }
458485
459 param_di_types[0] = return_type->di_type;
460 LLVMZigDISubroutineType *di_sub_type = LLVMZigCreateSubroutineType(g->dbuilder, import->di_file,
461 param_di_types, gen_param_count + 1, 0);
462
463 // Add debug info.486 // Add debug info.
464 unsigned line_number = node->line + 1;487 unsigned line_number = node->line + 1;
465 unsigned scope_line = line_number;488 unsigned scope_line = line_number;
...@@ -469,9 +492,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -469,9 +492,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
469 LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,492 LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,
470 import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "",493 import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
471 import->di_file, line_number,494 import->di_file, line_number,
472 di_sub_type, fn_table_entry->internal_linkage, 495 fn_type->di_type, fn_table_entry->internal_linkage,
473 is_definition, scope_line, flags, is_optimized, fn_table_entry->fn_value);496 is_definition, scope_line, flags, is_optimized, fn_table_entry->fn_value);
474 fn_type->di_type = LLVMZigSubroutineToType(di_sub_type);
475 if (fn_table_entry->fn_def_node) {497 if (fn_table_entry->fn_def_node) {
476 BlockContext *context = new_block_context(fn_table_entry->fn_def_node, import->block_context);498 BlockContext *context = new_block_context(fn_table_entry->fn_def_node, import->block_context);
477 fn_table_entry->fn_def_node->data.fn_def.block_context = context;499 fn_table_entry->fn_def_node->data.fn_def.block_context = context;
...@@ -802,7 +824,6 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,...@@ -802,7 +824,6 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
802 fn_table_entry->fn_def_node = fn_def_node;824 fn_table_entry->fn_def_node = fn_def_node;
803 fn_table_entry->internal_linkage = !is_c_compat;825 fn_table_entry->internal_linkage = !is_c_compat;
804 fn_table_entry->is_extern = extern_node;826 fn_table_entry->is_extern = extern_node;
805 fn_table_entry->calling_convention = is_c_compat ? LLVMCCallConv : LLVMFastCallConv;
806 fn_table_entry->label_table.init(8);827 fn_table_entry->label_table.init(8);
807 fn_table_entry->member_of_struct = struct_type;828 fn_table_entry->member_of_struct = struct_type;
808829
...@@ -1677,6 +1698,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,...@@ -1677,6 +1698,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
16771698
1678 auto fn_table_entry = import->fn_table.maybe_get(variable_name);1699 auto fn_table_entry = import->fn_table.maybe_get(variable_name);
1679 if (fn_table_entry) {1700 if (fn_table_entry) {
1701 node->data.symbol_expr.fn_entry = fn_table_entry->value;
1680 return resolve_expr_const_val_as_fn(g, node, fn_table_entry->value);1702 return resolve_expr_const_val_as_fn(g, node, fn_table_entry->value);
1681 }1703 }
16821704
...@@ -2823,15 +2845,21 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import...@@ -2823,15 +2845,21 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
2823 // otherwise we treat this as a function pointer.2845 // otherwise we treat this as a function pointer.
2824 ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val;2846 ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val;
28252847
2826 if (!const_val->ok) {2848 if (const_val->ok) {
2827 add_node_error(g, node, buf_sprintf("function pointers not yet supported"));2849 if (invoke_type_entry->id == TypeTableEntryIdMetaType) {
2828 return g->builtin_types.entry_invalid;2850 return analyze_cast_expr(g, import, context, node);
2851 } else if (invoke_type_entry->id == TypeTableEntryIdFn) {
2852 return analyze_fn_call_raw(g, import, context, expected_type, node, const_val->data.x_fn, nullptr);
2853 } else {
2854 add_node_error(g, fn_ref_expr,
2855 buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
2856 return g->builtin_types.entry_invalid;
2857 }
2829 }2858 }
28302859
2831 if (invoke_type_entry->id == TypeTableEntryIdMetaType) {2860 // function pointer
2832 return analyze_cast_expr(g, import, context, node);2861 if (invoke_type_entry->id == TypeTableEntryIdFn) {
2833 } else if (invoke_type_entry->id == TypeTableEntryIdFn) {2862 return invoke_type_entry->data.fn.return_type;
2834 return analyze_fn_call_raw(g, import, context, expected_type, node, const_val->data.x_fn, nullptr);
2835 } else {2863 } else {
2836 add_node_error(g, fn_ref_expr,2864 add_node_error(g, fn_ref_expr,
2837 buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));2865 buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
src/codegen.cpp+42-50
...@@ -82,24 +82,11 @@ static TypeTableEntry *get_type_for_type_node(AstNode *node) {...@@ -82,24 +82,11 @@ static TypeTableEntry *get_type_for_type_node(AstNode *node) {
82 return const_val->data.x_type;82 return const_val->data.x_type;
83}83}
8484
85static bool type_is_unreachable(CodeGen *g, AstNode *type_node) {
86 return get_type_for_type_node(type_node)->id == TypeTableEntryIdUnreachable;
87}
88
89static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) {85static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) {
90 assert(param_decl_node->type == NodeTypeParamDecl);86 assert(param_decl_node->type == NodeTypeParamDecl);
91 return get_type_for_type_node(param_decl_node->data.param_decl.type)->size_in_bits == 0;87 return get_type_for_type_node(param_decl_node->data.param_decl.type)->size_in_bits == 0;
92}88}
9389
94static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) {
95 int result = 0;
96 for (int i = 0; i < params->length; i += 1) {
97 if (!is_param_decl_type_void(g, params->at(i)))
98 result += 1;
99 }
100 return result;
101}
102
103static void add_debug_source_node(CodeGen *g, AstNode *node) {90static void add_debug_source_node(CodeGen *g, AstNode *node) {
104 if (!g->cur_block_context)91 if (!g->cur_block_context)
105 return;92 return;
...@@ -446,24 +433,25 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -446,24 +433,25 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
446 }433 }
447 }434 }
448435
449 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);436 TypeTableEntry *fn_type;
450 AstNodeFnProto *fn_proto_data = &fn_table_entry->proto_node->data.fn_proto;437 LLVMValueRef fn_val;
438 if (fn_table_entry) {
439 fn_val = fn_table_entry->fn_value;
440 fn_type = fn_table_entry->type_entry;
441 } else {
442 fn_val = gen_expr(g, fn_ref_expr);
443 fn_type = get_expr_type(fn_ref_expr);
444 }
451445
452 int expected_param_count = fn_proto_data->params.length;446 int expected_param_count = fn_type->data.fn.src_param_count;
453 int fn_call_param_count = node->data.fn_call_expr.params.length;447 int fn_call_param_count = node->data.fn_call_expr.params.length;
454 int actual_param_count = fn_call_param_count + (struct_type ? 1 : 0);448 int actual_param_count = fn_call_param_count + (struct_type ? 1 : 0);
455 bool is_var_args = fn_proto_data->is_var_args;449 bool is_var_args = fn_type->data.fn.is_var_args;
456 assert((is_var_args && actual_param_count >= expected_param_count) ||450 assert((is_var_args && actual_param_count >= expected_param_count) ||
457 actual_param_count == expected_param_count);451 actual_param_count == expected_param_count);
458452
459 // don't really include void values453 // don't really include void values
460 int gen_param_count;454 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
461 if (is_var_args) {
462 gen_param_count = actual_param_count;
463 } else {
464 gen_param_count = count_non_void_params(g, &fn_table_entry->proto_node->data.fn_proto.params);
465 }
466 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(gen_param_count);
467455
468 int gen_param_index = 0;456 int gen_param_index = 0;
469 if (struct_type) {457 if (struct_type) {
...@@ -474,19 +462,18 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -474,19 +462,18 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
474 for (int i = 0; i < fn_call_param_count; i += 1) {462 for (int i = 0; i < fn_call_param_count; i += 1) {
475 AstNode *expr_node = node->data.fn_call_expr.params.at(i);463 AstNode *expr_node = node->data.fn_call_expr.params.at(i);
476 LLVMValueRef param_value = gen_expr(g, expr_node);464 LLVMValueRef param_value = gen_expr(g, expr_node);
477 if (is_var_args ||465 TypeTableEntry *param_type = get_expr_type(expr_node);
478 !is_param_decl_type_void(g, fn_table_entry->proto_node->data.fn_proto.params.at(i)))466 if (is_var_args || param_type->size_in_bits > 0) {
479 {
480 gen_param_values[gen_param_index] = param_value;467 gen_param_values[gen_param_index] = param_value;
481 gen_param_index += 1;468 gen_param_index += 1;
482 }469 }
483 }470 }
484471
485 add_debug_source_node(g, node);472 add_debug_source_node(g, node);
486 LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_table_entry->fn_value,473 LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val,
487 gen_param_values, gen_param_count, fn_table_entry->calling_convention, "");474 gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
488475
489 if (type_is_unreachable(g, fn_table_entry->proto_node->data.fn_proto.return_type)) {476 if (fn_type->data.fn.return_type->id == TypeTableEntryIdUnreachable) {
490 return LLVMBuildUnreachable(g->builder);477 return LLVMBuildUnreachable(g->builder);
491 } else {478 } else {
492 return result;479 return result;
...@@ -1243,7 +1230,7 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {...@@ -1243,7 +1230,7 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
1243 LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");1230 LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");
1244 LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");1231 LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");
1245 LLVMBasicBlockRef end_block;1232 LLVMBasicBlockRef end_block;
1246 1233
1247 bool non_null_reachable = get_expr_type(op1_node)->id != TypeTableEntryIdUnreachable;1234 bool non_null_reachable = get_expr_type(op1_node)->id != TypeTableEntryIdUnreachable;
1248 bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;1235 bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;
1249 bool end_reachable = non_null_reachable || null_reachable;1236 bool end_reachable = non_null_reachable || null_reachable;
...@@ -1951,27 +1938,31 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {...@@ -1951,27 +1938,31 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
1951}1938}
19521939
1953static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {1940static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
1954 VariableTableEntry *variable = find_variable(1941 assert(node->type == NodeTypeSymbol);
1955 get_resolved_expr(node)->block_context,1942 VariableTableEntry *variable = node->data.symbol_expr.variable;
1956 &node->data.symbol_expr.symbol);1943 if (variable) {
1957 assert(variable);1944 if (variable->type->size_in_bits == 0) {
1958 if (variable->type->size_in_bits == 0) {1945 return nullptr;
1959 return nullptr;1946 } else if (variable->is_ptr) {
1960 } else if (variable->is_ptr) {1947 assert(variable->value_ref);
1961 assert(variable->value_ref);1948 if (variable->type->id == TypeTableEntryIdArray) {
1962 if (variable->type->id == TypeTableEntryIdArray) {1949 return variable->value_ref;
1963 return variable->value_ref;1950 } else if (variable->type->id == TypeTableEntryIdStruct ||
1964 } else if (variable->type->id == TypeTableEntryIdStruct ||1951 variable->type->id == TypeTableEntryIdMaybe)
1965 variable->type->id == TypeTableEntryIdMaybe)1952 {
1966 {1953 return variable->value_ref;
1967 return variable->value_ref;1954 } else {
1955 add_debug_source_node(g, node);
1956 return LLVMBuildLoad(g->builder, variable->value_ref, "");
1957 }
1968 } else {1958 } else {
1969 add_debug_source_node(g, node);1959 return variable->value_ref;
1970 return LLVMBuildLoad(g->builder, variable->value_ref, "");
1971 }1960 }
1972 } else {
1973 return variable->value_ref;
1974 }1961 }
1962
1963 FnTableEntry *fn_entry = node->data.symbol_expr.fn_entry;
1964 assert(fn_entry);
1965 return fn_entry->fn_value;
1975}1966}
19761967
1977static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {1968static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
...@@ -2714,6 +2705,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,...@@ -2714,6 +2705,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
2714 import_entry->line_offsets = tokenization.line_offsets;2705 import_entry->line_offsets = tokenization.line_offsets;
2715 import_entry->path = full_path;2706 import_entry->path = full_path;
2716 import_entry->fn_table.init(32);2707 import_entry->fn_table.init(32);
2708 import_entry->fn_type_table.init(32);
27172709
2718 import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color,2710 import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color,
2719 &g->next_node_index);2711 &g->next_node_index);
...@@ -3098,7 +3090,7 @@ void codegen_link(CodeGen *g, const char *out_file) {...@@ -3098,7 +3090,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
3098 // invoke `ar`3090 // invoke `ar`
3099 // example:3091 // example:
3100 // # static link into libfoo.a3092 // # static link into libfoo.a
3101 // ar rcs libfoo.a foo1.o foo2.o 3093 // ar rcs libfoo.a foo1.o foo2.o
3102 zig_panic("TODO invoke ar");3094 zig_panic("TODO invoke ar");
3103 return;3095 return;
3104 }3096 }
src/zig_llvm.cpp+6-9
...@@ -284,7 +284,7 @@ void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type,...@@ -284,7 +284,7 @@ void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type,
284 reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(fields));284 reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(fields));
285}285}
286286
287LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,287LLVMZigDIType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
288 LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags)288 LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags)
289{289{
290 SmallVector<Metadata *, 8> types;290 SmallVector<Metadata *, 8> types;
...@@ -297,7 +297,8 @@ LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder...@@ -297,7 +297,8 @@ LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder
297 reinterpret_cast<DIFile*>(file),297 reinterpret_cast<DIFile*>(file),
298 dibuilder->getOrCreateTypeArray(types),298 dibuilder->getOrCreateTypeArray(types),
299 flags);299 flags);
300 return reinterpret_cast<LLVMZigDISubroutineType*>(subroutine_type);300 DIType *ditype = subroutine_type;
301 return reinterpret_cast<LLVMZigDIType*>(ditype);
301}302}
302303
303unsigned LLVMZigEncoding_DW_ATE_unsigned(void) {304unsigned LLVMZigEncoding_DW_ATE_unsigned(void) {
...@@ -388,11 +389,6 @@ LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram) {...@@ -388,11 +389,6 @@ LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram) {
388 return reinterpret_cast<LLVMZigDIScope*>(scope);389 return reinterpret_cast<LLVMZigDIScope*>(scope);
389}390}
390391
391LLVMZigDIType *LLVMZigSubroutineToType(LLVMZigDISubroutineType *subrtype) {
392 DIType *di_type = reinterpret_cast<DISubroutineType*>(subrtype);
393 return reinterpret_cast<LLVMZigDIType*>(di_type);
394}
395
396LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type) {392LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type) {
397 DIScope *scope = reinterpret_cast<DIType*>(type);393 DIScope *scope = reinterpret_cast<DIType*>(type);
398 return reinterpret_cast<LLVMZigDIScope*>(scope);394 return reinterpret_cast<LLVMZigDIScope*>(scope);
...@@ -416,16 +412,17 @@ LLVMZigDIFile *LLVMZigCreateFile(LLVMZigDIBuilder *dibuilder, const char *filena...@@ -416,16 +412,17 @@ LLVMZigDIFile *LLVMZigCreateFile(LLVMZigDIBuilder *dibuilder, const char *filena
416412
417LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,413LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,
418 const char *name, const char *linkage_name, LLVMZigDIFile *file, unsigned lineno,414 const char *name, const char *linkage_name, LLVMZigDIFile *file, unsigned lineno,
419 LLVMZigDISubroutineType *ty, bool is_local_to_unit, bool is_definition, unsigned scope_line,415 LLVMZigDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,
420 unsigned flags, bool is_optimized, LLVMValueRef function)416 unsigned flags, bool is_optimized, LLVMValueRef function)
421{417{
422 Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(function));418 Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(function));
419 DISubroutineType *di_sub_type = static_cast<DISubroutineType*>(reinterpret_cast<DIType*>(fn_di_type));
423 DISubprogram *result = reinterpret_cast<DIBuilder*>(dibuilder)->createFunction(420 DISubprogram *result = reinterpret_cast<DIBuilder*>(dibuilder)->createFunction(
424 reinterpret_cast<DIScope*>(scope),421 reinterpret_cast<DIScope*>(scope),
425 name, linkage_name,422 name, linkage_name,
426 reinterpret_cast<DIFile*>(file),423 reinterpret_cast<DIFile*>(file),
427 lineno,424 lineno,
428 reinterpret_cast<DISubroutineType*>(ty),425 di_sub_type,
429 is_local_to_unit, is_definition, scope_line, flags, is_optimized, unwrapped_function);426 is_local_to_unit, is_definition, scope_line, flags, is_optimized, unwrapped_function);
430 return reinterpret_cast<LLVMZigDISubprogram*>(result);427 return reinterpret_cast<LLVMZigDISubprogram*>(result);
431}428}
src/zig_llvm.hpp+2-3
...@@ -81,7 +81,7 @@ void LLVMZigReplaceTemporary(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type,...@@ -81,7 +81,7 @@ void LLVMZigReplaceTemporary(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type,
81void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type,81void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type,
82 LLVMZigDIType **types_array, int types_array_len);82 LLVMZigDIType **types_array, int types_array_len);
8383
84LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,84LLVMZigDIType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
85 LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags);85 LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags);
8686
87unsigned LLVMZigEncoding_DW_ATE_unsigned(void);87unsigned LLVMZigEncoding_DW_ATE_unsigned(void);
...@@ -101,7 +101,6 @@ LLVMZigDIScope *LLVMZigCompileUnitToScope(LLVMZigDICompileUnit *compile_unit);...@@ -101,7 +101,6 @@ LLVMZigDIScope *LLVMZigCompileUnitToScope(LLVMZigDICompileUnit *compile_unit);
101LLVMZigDIScope *LLVMZigFileToScope(LLVMZigDIFile *difile);101LLVMZigDIScope *LLVMZigFileToScope(LLVMZigDIFile *difile);
102LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram);102LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram);
103LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type);103LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type);
104LLVMZigDIType *LLVMZigSubroutineToType(LLVMZigDISubroutineType *subrtype);
105104
106LLVMZigDILocalVariable *LLVMZigCreateLocalVariable(LLVMZigDIBuilder *dbuilder, unsigned tag,105LLVMZigDILocalVariable *LLVMZigCreateLocalVariable(LLVMZigDIBuilder *dbuilder, unsigned tag,
107 LLVMZigDIScope *scope, const char *name, LLVMZigDIFile *file, unsigned line_no,106 LLVMZigDIScope *scope, const char *name, LLVMZigDIFile *file, unsigned line_no,
...@@ -119,7 +118,7 @@ LLVMZigDIFile *LLVMZigCreateFile(LLVMZigDIBuilder *dibuilder, const char *filena...@@ -119,7 +118,7 @@ LLVMZigDIFile *LLVMZigCreateFile(LLVMZigDIBuilder *dibuilder, const char *filena
119118
120LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,119LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,
121 const char *name, const char *linkage_name, LLVMZigDIFile *file, unsigned lineno,120 const char *name, const char *linkage_name, LLVMZigDIFile *file, unsigned lineno,
122 LLVMZigDISubroutineType *ty, bool is_local_to_unit, bool is_definition, unsigned scope_line,121 LLVMZigDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,
123 unsigned flags, bool is_optimized, LLVMValueRef function);122 unsigned flags, bool is_optimized, LLVMValueRef function);
124123
125void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder);124void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder);
std/bootstrap.zig+1-1
...@@ -15,7 +15,7 @@ export fn _start() unreachable => {...@@ -15,7 +15,7 @@ export fn _start() unreachable => {
15 call_main()15 call_main()
16}16}
1717
18fn strlen(ptr: &u8) usize => {18fn strlen(ptr: &const u8) usize => {
19 var count: usize = 0;19 var count: usize = 0;
20 while (ptr[count] != 0) {20 while (ptr[count] != 0) {
21 count += 1;21 count += 1;
test/run_tests.cpp+18
...@@ -1162,6 +1162,24 @@ pub fn main(args: [][]u8) i32 => {...@@ -1162,6 +1162,24 @@ pub fn main(args: [][]u8) i32 => {
1162 return 0;1162 return 0;
1163}1163}
1164 )SOURCE", "9\n8\n7\n6\n0\n1\n2\n3\n9\n8\n7\n6\n0\n1\n2\n3\n");1164 )SOURCE", "9\n8\n7\n6\n0\n1\n2\n3\n9\n8\n7\n6\n0\n1\n2\n3\n");
1165
1166 add_simple_case("function pointers", R"SOURCE(
1167import "std.zig";
1168
1169pub fn main(args: [][]u8) i32 => {
1170 const fns = []@typeof(fn1) { fn1, fn2, fn3, fn4, };
1171 for (f, fns) {
1172 print_u64(f());
1173 print_str("\n");
1174 }
1175 return 0;
1176}
1177
1178fn fn1() u32 => {5}
1179fn fn2() u32 => {6}
1180fn fn3() u32 => {7}
1181fn fn4() u32 => {8}
1182 )SOURCE", "5\n6\n7\n8\n");
1165}1183}
11661184
11671185