| author | |
| committer | |
| log | 32821e7098ba29c30e458f555f62954ce54dcb1a |
| tree | efc8326896f255c9ba6f12e28c4e83612242271c |
| parent | 3a326d50051ad8b65639e5e2bbe45e41a8b35591 |
See #147 files changed, 136 insertions(+), 97 deletions(-)
src/all_types.hpp+11-6| ... | ... | @@ -566,6 +566,7 @@ struct AstNodeSymbolExpr { |
| 566 | 566 | // populated by semantic analyzer |
| 567 | 567 | Expr resolved_expr; |
| 568 | 568 | VariableTableEntry *variable; |
| 569 | FnTableEntry *fn_entry; | |
| 569 | 570 | }; |
| 570 | 571 | |
| 571 | 572 | struct AstNodeBoolLiteral { |
| ... | ... | @@ -720,7 +721,12 @@ struct TypeTableEntryEnum { |
| 720 | 721 | struct TypeTableEntryFn { |
| 721 | 722 | TypeTableEntry *return_type; |
| 722 | 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 | }; |
| 725 | 731 | |
| 726 | 732 | enum TypeTableEntryId { |
| ... | ... | @@ -784,6 +790,7 @@ struct ImportTableEntry { |
| 784 | 790 | |
| 785 | 791 | // reminder: hash tables must be initialized before use |
| 786 | 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 | }; |
| 788 | 795 | |
| 789 | 796 | struct LabelTableEntry { |
| ... | ... | @@ -797,17 +804,15 @@ struct FnTableEntry { |
| 797 | 804 | LLVMValueRef fn_value; |
| 798 | 805 | AstNode *proto_node; |
| 799 | 806 | AstNode *fn_def_node; |
| 800 | bool is_extern; | |
| 801 | bool internal_linkage; | |
| 802 | unsigned calling_convention; | |
| 803 | 807 | ImportTableEntry *import_entry; |
| 804 | bool is_naked; | |
| 805 | bool is_inline; | |
| 806 | 808 | // Required to be a pre-order traversal of the AST. (parents must come before children) |
| 807 | 809 | ZigList<BlockContext *> all_block_contexts; |
| 808 | 810 | TypeTableEntry *member_of_struct; |
| 809 | 811 | Buf symbol_name; |
| 810 | 812 | TypeTableEntry *type_entry; // function type |
| 813 | bool is_inline; | |
| 814 | bool internal_linkage; | |
| 815 | bool is_extern; | |
| 811 | 816 | |
| 812 | 817 | // reminder: hash tables must be initialized before use |
| 813 | 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 | 348 | assert(node->type == NodeTypeFnProto); |
| 349 | 349 | AstNodeFnProto *fn_proto = &node->data.fn_proto; |
| 350 | 350 | |
| 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 | 354 | for (int i = 0; i < fn_proto->directives->length; i += 1) { |
| 352 | 355 | AstNode *directive_node = fn_proto->directives->at(i); |
| 353 | 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 | 359 | Buf *attr_name = &directive_node->data.directive.param; |
| 357 | 360 | if (fn_table_entry->fn_def_node) { |
| 358 | 361 | if (buf_eql_str(attr_name, "naked")) { |
| 359 | fn_table_entry->is_naked = true; | |
| 362 | fn_type->data.fn.is_naked = true; | |
| 360 | 363 | } else if (buf_eql_str(attr_name, "inline")) { |
| 361 | 364 | fn_table_entry->is_inline = true; |
| 362 | 365 | } else { |
| ... | ... | @@ -373,20 +376,24 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 373 | 376 | } |
| 374 | 377 | } |
| 375 | 378 | |
| 376 | int param_count = node->data.fn_proto.params.length; | |
| 379 | int src_param_count = node->data.fn_proto.params.length; | |
| 377 | 380 | |
| 378 | TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); | |
| 379 | fn_type->data.fn.param_count = param_count; | |
| 380 | fn_type->data.fn.param_types = allocate<TypeTableEntry*>(param_count); | |
| 381 | fn_type->size_in_bits = g->pointer_size_bytes * 8; | |
| 382 | fn_type->align_in_bits = g->pointer_size_bytes * 8; | |
| 383 | fn_type->data.fn.src_param_count = src_param_count; | |
| 384 | fn_type->data.fn.param_types = allocate<TypeTableEntry*>(src_param_count); | |
| 381 | 385 | |
| 382 | 386 | fn_table_entry->type_entry = fn_type; |
| 383 | 387 | |
| 384 | 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 | 393 | int gen_param_count = 0; |
| 387 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(param_count); | |
| 388 | LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(1 + param_count); | |
| 389 | for (int i = 0; i < param_count; i += 1) { | |
| 394 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(src_param_count); | |
| 395 | LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(1 + src_param_count); | |
| 396 | for (int i = 0; i < src_param_count; i += 1) { | |
| 390 | 397 | AstNode *child = node->data.fn_proto.params.at(i); |
| 391 | 398 | assert(child->type == NodeTypeParamDecl); |
| 392 | 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 | 423 | } |
| 417 | 424 | } |
| 418 | 425 | |
| 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 | 433 | TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context, |
| 420 | 434 | node->data.fn_proto.return_type); |
| 421 | 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 | 446 | return; |
| 433 | 447 | } |
| 434 | 448 | |
| 435 | fn_type->type_ref = LLVMFunctionType(return_type->type_ref, gen_param_types, gen_param_count, | |
| 436 | fn_proto->is_var_args); | |
| 449 | auto table_entry = import->fn_type_table.maybe_get(&fn_type->name); | |
| 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 | ||
| 437 | 464 | |
| 438 | 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); | |
| 440 | 467 | |
| 441 | 468 | if (fn_table_entry->is_inline) { |
| 442 | 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 | 472 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute); |
| 446 | 473 | } |
| 447 | 474 | |
| ... | ... | @@ -451,15 +478,11 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 451 | 478 | if (return_type->id == TypeTableEntryIdUnreachable) { |
| 452 | 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 | 482 | if (!fn_table_entry->is_extern) { |
| 456 | 483 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute); |
| 457 | 484 | } |
| 458 | 485 | |
| 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 | 486 | // Add debug info. |
| 464 | 487 | unsigned line_number = node->line + 1; |
| 465 | 488 | unsigned scope_line = line_number; |
| ... | ... | @@ -469,9 +492,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 469 | 492 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, |
| 470 | 493 | import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "", |
| 471 | 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 | 496 | is_definition, scope_line, flags, is_optimized, fn_table_entry->fn_value); |
| 474 | fn_type->di_type = LLVMZigSubroutineToType(di_sub_type); | |
| 475 | 497 | if (fn_table_entry->fn_def_node) { |
| 476 | 498 | BlockContext *context = new_block_context(fn_table_entry->fn_def_node, import->block_context); |
| 477 | 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 | 824 | fn_table_entry->fn_def_node = fn_def_node; |
| 803 | 825 | fn_table_entry->internal_linkage = !is_c_compat; |
| 804 | 826 | fn_table_entry->is_extern = extern_node; |
| 805 | fn_table_entry->calling_convention = is_c_compat ? LLVMCCallConv : LLVMFastCallConv; | |
| 806 | 827 | fn_table_entry->label_table.init(8); |
| 807 | 828 | fn_table_entry->member_of_struct = struct_type; |
| 808 | 829 | |
| ... | ... | @@ -1677,6 +1698,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 1677 | 1698 | |
| 1678 | 1699 | auto fn_table_entry = import->fn_table.maybe_get(variable_name); |
| 1679 | 1700 | if (fn_table_entry) { |
| 1701 | node->data.symbol_expr.fn_entry = fn_table_entry->value; | |
| 1680 | 1702 | return resolve_expr_const_val_as_fn(g, node, fn_table_entry->value); |
| 1681 | 1703 | } |
| 1682 | 1704 | |
| ... | ... | @@ -2823,15 +2845,21 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 2823 | 2845 | // otherwise we treat this as a function pointer. |
| 2824 | 2846 | ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val; |
| 2825 | 2847 | |
| 2826 | if (!const_val->ok) { | |
| 2827 | add_node_error(g, node, buf_sprintf("function pointers not yet supported")); | |
| 2828 | return g->builtin_types.entry_invalid; | |
| 2848 | if (const_val->ok) { | |
| 2849 | if (invoke_type_entry->id == TypeTableEntryIdMetaType) { | |
| 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 | } |
| 2830 | 2859 | |
| 2831 | if (invoke_type_entry->id == TypeTableEntryIdMetaType) { | |
| 2832 | return analyze_cast_expr(g, import, context, node); | |
| 2833 | } else if (invoke_type_entry->id == TypeTableEntryIdFn) { | |
| 2834 | return analyze_fn_call_raw(g, import, context, expected_type, node, const_val->data.x_fn, nullptr); | |
| 2860 | // function pointer | |
| 2861 | if (invoke_type_entry->id == TypeTableEntryIdFn) { | |
| 2862 | return invoke_type_entry->data.fn.return_type; | |
| 2835 | 2863 | } else { |
| 2836 | 2864 | add_node_error(g, fn_ref_expr, |
| 2837 | 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 | 82 | return const_val->data.x_type; |
| 83 | 83 | } |
| 84 | 84 | |
| 85 | static bool type_is_unreachable(CodeGen *g, AstNode *type_node) { | |
| 86 | return get_type_for_type_node(type_node)->id == TypeTableEntryIdUnreachable; | |
| 87 | } | |
| 88 | ||
| 89 | 85 | static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) { |
| 90 | 86 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 91 | 87 | return get_type_for_type_node(param_decl_node->data.param_decl.type)->size_in_bits == 0; |
| 92 | 88 | } |
| 93 | 89 | |
| 94 | static 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 | ||
| 103 | 90 | static void add_debug_source_node(CodeGen *g, AstNode *node) { |
| 104 | 91 | if (!g->cur_block_context) |
| 105 | 92 | return; |
| ... | ... | @@ -446,24 +433,25 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 446 | 433 | } |
| 447 | 434 | } |
| 448 | 435 | |
| 449 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); | |
| 450 | AstNodeFnProto *fn_proto_data = &fn_table_entry->proto_node->data.fn_proto; | |
| 436 | TypeTableEntry *fn_type; | |
| 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 | } | |
| 451 | 445 | |
| 452 | int expected_param_count = fn_proto_data->params.length; | |
| 446 | int expected_param_count = fn_type->data.fn.src_param_count; | |
| 453 | 447 | int fn_call_param_count = node->data.fn_call_expr.params.length; |
| 454 | 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 | 450 | assert((is_var_args && actual_param_count >= expected_param_count) || |
| 457 | 451 | actual_param_count == expected_param_count); |
| 458 | 452 | |
| 459 | 453 | // don't really include void values |
| 460 | int gen_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); | |
| 454 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); | |
| 467 | 455 | |
| 468 | 456 | int gen_param_index = 0; |
| 469 | 457 | if (struct_type) { |
| ... | ... | @@ -474,19 +462,18 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 474 | 462 | for (int i = 0; i < fn_call_param_count; i += 1) { |
| 475 | 463 | AstNode *expr_node = node->data.fn_call_expr.params.at(i); |
| 476 | 464 | LLVMValueRef param_value = gen_expr(g, expr_node); |
| 477 | if (is_var_args || | |
| 478 | !is_param_decl_type_void(g, fn_table_entry->proto_node->data.fn_proto.params.at(i))) | |
| 479 | { | |
| 465 | TypeTableEntry *param_type = get_expr_type(expr_node); | |
| 466 | if (is_var_args || param_type->size_in_bits > 0) { | |
| 480 | 467 | gen_param_values[gen_param_index] = param_value; |
| 481 | 468 | gen_param_index += 1; |
| 482 | 469 | } |
| 483 | 470 | } |
| 484 | 471 | |
| 485 | 472 | add_debug_source_node(g, node); |
| 486 | LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_table_entry->fn_value, | |
| 487 | gen_param_values, gen_param_count, fn_table_entry->calling_convention, ""); | |
| 473 | LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val, | |
| 474 | gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, ""); | |
| 488 | 475 | |
| 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 | 477 | return LLVMBuildUnreachable(g->builder); |
| 491 | 478 | } else { |
| 492 | 479 | return result; |
| ... | ... | @@ -1243,7 +1230,7 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { |
| 1243 | 1230 | LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull"); |
| 1244 | 1231 | LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull"); |
| 1245 | 1232 | LLVMBasicBlockRef end_block; |
| 1246 | ||
| 1233 | ||
| 1247 | 1234 | bool non_null_reachable = get_expr_type(op1_node)->id != TypeTableEntryIdUnreachable; |
| 1248 | 1235 | bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable; |
| 1249 | 1236 | bool end_reachable = non_null_reachable || null_reachable; |
| ... | ... | @@ -1951,27 +1938,31 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) { |
| 1951 | 1938 | } |
| 1952 | 1939 | |
| 1953 | 1940 | static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { |
| 1954 | VariableTableEntry *variable = find_variable( | |
| 1955 | get_resolved_expr(node)->block_context, | |
| 1956 | &node->data.symbol_expr.symbol); | |
| 1957 | assert(variable); | |
| 1958 | if (variable->type->size_in_bits == 0) { | |
| 1959 | return nullptr; | |
| 1960 | } else if (variable->is_ptr) { | |
| 1961 | assert(variable->value_ref); | |
| 1962 | if (variable->type->id == TypeTableEntryIdArray) { | |
| 1963 | return variable->value_ref; | |
| 1964 | } else if (variable->type->id == TypeTableEntryIdStruct || | |
| 1965 | variable->type->id == TypeTableEntryIdMaybe) | |
| 1966 | { | |
| 1967 | return variable->value_ref; | |
| 1941 | assert(node->type == NodeTypeSymbol); | |
| 1942 | VariableTableEntry *variable = node->data.symbol_expr.variable; | |
| 1943 | if (variable) { | |
| 1944 | if (variable->type->size_in_bits == 0) { | |
| 1945 | return nullptr; | |
| 1946 | } else if (variable->is_ptr) { | |
| 1947 | assert(variable->value_ref); | |
| 1948 | if (variable->type->id == TypeTableEntryIdArray) { | |
| 1949 | return variable->value_ref; | |
| 1950 | } else if (variable->type->id == TypeTableEntryIdStruct || | |
| 1951 | variable->type->id == TypeTableEntryIdMaybe) | |
| 1952 | { | |
| 1953 | return variable->value_ref; | |
| 1954 | } else { | |
| 1955 | add_debug_source_node(g, node); | |
| 1956 | return LLVMBuildLoad(g->builder, variable->value_ref, ""); | |
| 1957 | } | |
| 1968 | 1958 | } else { |
| 1969 | add_debug_source_node(g, node); | |
| 1970 | return LLVMBuildLoad(g->builder, variable->value_ref, ""); | |
| 1959 | return 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 | } |
| 1976 | 1967 | |
| 1977 | 1968 | static 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 | 2705 | import_entry->line_offsets = tokenization.line_offsets; |
| 2715 | 2706 | import_entry->path = full_path; |
| 2716 | 2707 | import_entry->fn_table.init(32); |
| 2708 | import_entry->fn_type_table.init(32); | |
| 2717 | 2709 | |
| 2718 | 2710 | import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color, |
| 2719 | 2711 | &g->next_node_index); |
| ... | ... | @@ -3098,7 +3090,7 @@ void codegen_link(CodeGen *g, const char *out_file) { |
| 3098 | 3090 | // invoke `ar` |
| 3099 | 3091 | // example: |
| 3100 | 3092 | // # static link into libfoo.a |
| 3101 | // ar rcs libfoo.a foo1.o foo2.o | |
| 3093 | // ar rcs libfoo.a foo1.o foo2.o | |
| 3102 | 3094 | zig_panic("TODO invoke ar"); |
| 3103 | 3095 | return; |
| 3104 | 3096 | } |
src/zig_llvm.cpp+6-9| ... | ... | @@ -284,7 +284,7 @@ void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type, |
| 284 | 284 | reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(fields)); |
| 285 | 285 | } |
| 286 | 286 | |
| 287 | LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped, | |
| 287 | LLVMZigDIType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped, | |
| 288 | 288 | LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags) |
| 289 | 289 | { |
| 290 | 290 | SmallVector<Metadata *, 8> types; |
| ... | ... | @@ -297,7 +297,8 @@ LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder |
| 297 | 297 | reinterpret_cast<DIFile*>(file), |
| 298 | 298 | dibuilder->getOrCreateTypeArray(types), |
| 299 | 299 | flags); |
| 300 | return reinterpret_cast<LLVMZigDISubroutineType*>(subroutine_type); | |
| 300 | DIType *ditype = subroutine_type; | |
| 301 | return reinterpret_cast<LLVMZigDIType*>(ditype); | |
| 301 | 302 | } |
| 302 | 303 | |
| 303 | 304 | unsigned LLVMZigEncoding_DW_ATE_unsigned(void) { |
| ... | ... | @@ -388,11 +389,6 @@ LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram) { |
| 388 | 389 | return reinterpret_cast<LLVMZigDIScope*>(scope); |
| 389 | 390 | } |
| 390 | 391 | |
| 391 | LLVMZigDIType *LLVMZigSubroutineToType(LLVMZigDISubroutineType *subrtype) { | |
| 392 | DIType *di_type = reinterpret_cast<DISubroutineType*>(subrtype); | |
| 393 | return reinterpret_cast<LLVMZigDIType*>(di_type); | |
| 394 | } | |
| 395 | ||
| 396 | 392 | LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type) { |
| 397 | 393 | DIScope *scope = reinterpret_cast<DIType*>(type); |
| 398 | 394 | return reinterpret_cast<LLVMZigDIScope*>(scope); |
| ... | ... | @@ -416,16 +412,17 @@ LLVMZigDIFile *LLVMZigCreateFile(LLVMZigDIBuilder *dibuilder, const char *filena |
| 416 | 412 | |
| 417 | 413 | LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope, |
| 418 | 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 | 416 | unsigned flags, bool is_optimized, LLVMValueRef function) |
| 421 | 417 | { |
| 422 | 418 | Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(function)); |
| 419 | DISubroutineType *di_sub_type = static_cast<DISubroutineType*>(reinterpret_cast<DIType*>(fn_di_type)); | |
| 423 | 420 | DISubprogram *result = reinterpret_cast<DIBuilder*>(dibuilder)->createFunction( |
| 424 | 421 | reinterpret_cast<DIScope*>(scope), |
| 425 | 422 | name, linkage_name, |
| 426 | 423 | reinterpret_cast<DIFile*>(file), |
| 427 | 424 | lineno, |
| 428 | reinterpret_cast<DISubroutineType*>(ty), | |
| 425 | di_sub_type, | |
| 429 | 426 | is_local_to_unit, is_definition, scope_line, flags, is_optimized, unwrapped_function); |
| 430 | 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 | 81 | void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type, |
| 82 | 82 | LLVMZigDIType **types_array, int types_array_len); |
| 83 | 83 | |
| 84 | LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped, | |
| 84 | LLVMZigDIType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped, | |
| 85 | 85 | LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags); |
| 86 | 86 | |
| 87 | 87 | unsigned LLVMZigEncoding_DW_ATE_unsigned(void); |
| ... | ... | @@ -101,7 +101,6 @@ LLVMZigDIScope *LLVMZigCompileUnitToScope(LLVMZigDICompileUnit *compile_unit); |
| 101 | 101 | LLVMZigDIScope *LLVMZigFileToScope(LLVMZigDIFile *difile); |
| 102 | 102 | LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram); |
| 103 | 103 | LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type); |
| 104 | LLVMZigDIType *LLVMZigSubroutineToType(LLVMZigDISubroutineType *subrtype); | |
| 105 | 104 | |
| 106 | 105 | LLVMZigDILocalVariable *LLVMZigCreateLocalVariable(LLVMZigDIBuilder *dbuilder, unsigned tag, |
| 107 | 106 | LLVMZigDIScope *scope, const char *name, LLVMZigDIFile *file, unsigned line_no, |
| ... | ... | @@ -119,7 +118,7 @@ LLVMZigDIFile *LLVMZigCreateFile(LLVMZigDIBuilder *dibuilder, const char *filena |
| 119 | 118 | |
| 120 | 119 | LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope, |
| 121 | 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 | 122 | unsigned flags, bool is_optimized, LLVMValueRef function); |
| 124 | 123 | |
| 125 | 124 | void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder); |
std/bootstrap.zig+1-1| ... | ... | @@ -15,7 +15,7 @@ export fn _start() unreachable => { |
| 15 | 15 | call_main() |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | fn strlen(ptr: &u8) usize => { | |
| 18 | fn strlen(ptr: &const u8) usize => { | |
| 19 | 19 | var count: usize = 0; |
| 20 | 20 | while (ptr[count] != 0) { |
| 21 | 21 | count += 1; |
test/run_tests.cpp+18| ... | ... | @@ -1162,6 +1162,24 @@ pub fn main(args: [][]u8) i32 => { |
| 1162 | 1162 | return 0; |
| 1163 | 1163 | } |
| 1164 | 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( | |
| 1167 | import "std.zig"; | |
| 1168 | ||
| 1169 | pub 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 | ||
| 1178 | fn fn1() u32 => {5} | |
| 1179 | fn fn2() u32 => {6} | |
| 1180 | fn fn3() u32 => {7} | |
| 1181 | fn fn4() u32 => {8} | |
| 1182 | )SOURCE", "5\n6\n7\n8\n"); | |
| 1165 | 1183 | } |
| 1166 | 1184 | |
| 1167 | 1185 |