| ... | @@ -113,9 +113,30 @@ static AstNode *first_executing_node(AstNode *node) { | ... | @@ -113,9 +113,30 @@ static AstNode *first_executing_node(AstNode *node) { |
| 113 | zig_unreachable(); | 113 | zig_unreachable(); |
| 114 | } | 114 | } |
| 115 | | 115 | |
| 116 | static void mark_impure_fn(BlockContext *context) { | 116 | static void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node) { |
| 117 | if (context->fn_entry) { | 117 | if (!context->fn_entry) return; |
| 118 | context->fn_entry->is_pure = false; | 118 | if (!context->fn_entry->is_pure) return; |
| | 119 | |
| | 120 | context->fn_entry->is_pure = false; |
| | 121 | if (context->fn_entry->want_pure == WantPureTrue) { |
| | 122 | context->fn_entry->proto_node->data.fn_proto.skip = true; |
| | 123 | |
| | 124 | ErrorMsg *msg = add_node_error(g, context->fn_entry->proto_node, |
| | 125 | buf_sprintf("failed to evaluate function at compile time")); |
| | 126 | |
| | 127 | add_error_note(g, msg, node, |
| | 128 | buf_sprintf("unable to evaluate this expression at compile time")); |
| | 129 | |
| | 130 | if (context->fn_entry->want_pure_attr_node) { |
| | 131 | add_error_note(g, msg, context->fn_entry->want_pure_attr_node, |
| | 132 | buf_sprintf("required to be compile-time function here")); |
| | 133 | } |
| | 134 | |
| | 135 | if (context->fn_entry->want_pure_return_type) { |
| | 136 | add_error_note(g, msg, context->fn_entry->want_pure_return_type, |
| | 137 | buf_sprintf("required to be compile-time function because of return type '%s'", |
| | 138 | buf_ptr(&context->fn_entry->type_entry->data.fn.fn_type_id.return_type->name))); |
| | 139 | } |
| 119 | } | 140 | } |
| 120 | } | 141 | } |
| 121 | | 142 | |
| ... | @@ -659,7 +680,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry * | ... | @@ -659,7 +680,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry * |
| 659 | } | 680 | } |
| 660 | | 681 | |
| 661 | // accepts ownership of fn_type_id memory | 682 | // accepts ownership of fn_type_id memory |
| 662 | TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | 683 | TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_info) { |
| 663 | auto table_entry = g->fn_type_table.maybe_get(fn_type_id); | 684 | auto table_entry = g->fn_type_table.maybe_get(fn_type_id); |
| 664 | if (table_entry) { | 685 | if (table_entry) { |
| 665 | return table_entry->value; | 686 | return table_entry->value; |
| ... | @@ -704,65 +725,67 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -704,65 +725,67 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 704 | buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id->return_type->name)); | 725 | buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id->return_type->name)); |
| 705 | } | 726 | } |
| 706 | | 727 | |
| 707 | // next, loop over the parameters again and compute debug information | 728 | if (gen_debug_info) { |
| 708 | // and codegen information | 729 | // next, loop over the parameters again and compute debug information |
| 709 | bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type); | 730 | // and codegen information |
| 710 | // +1 for maybe making the first argument the return value | 731 | bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type); |
| 711 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count); | 732 | // +1 for maybe making the first argument the return value |
| 712 | // +1 because 0 is the return type and +1 for maybe making first arg ret val | 733 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count); |
| 713 | LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + fn_type_id->param_count); | 734 | // +1 because 0 is the return type and +1 for maybe making first arg ret val |
| 714 | param_di_types[0] = fn_type_id->return_type->di_type; | 735 | LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + fn_type_id->param_count); |
| 715 | int gen_param_index = 0; | 736 | param_di_types[0] = fn_type_id->return_type->di_type; |
| 716 | TypeTableEntry *gen_return_type; | 737 | int gen_param_index = 0; |
| 717 | if (!type_has_bits(fn_type_id->return_type)) { | 738 | TypeTableEntry *gen_return_type; |
| 718 | gen_return_type = g->builtin_types.entry_void; | 739 | if (!type_has_bits(fn_type_id->return_type)) { |
| 719 | } else if (first_arg_return) { | 740 | gen_return_type = g->builtin_types.entry_void; |
| 720 | TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); | 741 | } else if (first_arg_return) { |
| 721 | gen_param_types[gen_param_index] = gen_type->type_ref; | 742 | TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); |
| 722 | gen_param_index += 1; | | |
| 723 | // after the gen_param_index += 1 because 0 is the return type | | |
| 724 | param_di_types[gen_param_index] = gen_type->di_type; | | |
| 725 | gen_return_type = g->builtin_types.entry_void; | | |
| 726 | } else { | | |
| 727 | gen_return_type = fn_type_id->return_type; | | |
| 728 | } | | |
| 729 | fn_type->data.fn.gen_return_type = gen_return_type; | | |
| 730 | | | |
| 731 | fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count); | | |
| 732 | for (int i = 0; i < fn_type_id->param_count; i += 1) { | | |
| 733 | FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; | | |
| 734 | TypeTableEntry *type_entry = src_param_info->type; | | |
| 735 | FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; | | |
| 736 | | | |
| 737 | gen_param_info->src_index = i; | | |
| 738 | gen_param_info->gen_index = -1; | | |
| 739 | | | |
| 740 | assert(type_is_complete(type_entry)); | | |
| 741 | if (type_has_bits(type_entry)) { | | |
| 742 | TypeTableEntry *gen_type; | | |
| 743 | if (handle_is_ptr(type_entry)) { | | |
| 744 | gen_type = get_pointer_to_type(g, type_entry, true); | | |
| 745 | gen_param_info->is_byval = true; | | |
| 746 | } else { | | |
| 747 | gen_type = type_entry; | | |
| 748 | } | | |
| 749 | gen_param_types[gen_param_index] = gen_type->type_ref; | 743 | gen_param_types[gen_param_index] = gen_type->type_ref; |
| 750 | gen_param_info->gen_index = gen_param_index; | | |
| 751 | gen_param_info->type = gen_type; | | |
| 752 | | | |
| 753 | gen_param_index += 1; | 744 | gen_param_index += 1; |
| 754 | | | |
| 755 | // after the gen_param_index += 1 because 0 is the return type | 745 | // after the gen_param_index += 1 because 0 is the return type |
| 756 | param_di_types[gen_param_index] = gen_type->di_type; | 746 | param_di_types[gen_param_index] = gen_type->di_type; |
| | 747 | gen_return_type = g->builtin_types.entry_void; |
| | 748 | } else { |
| | 749 | gen_return_type = fn_type_id->return_type; |
| 757 | } | 750 | } |
| 758 | } | 751 | fn_type->data.fn.gen_return_type = gen_return_type; |
| | 752 | |
| | 753 | fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count); |
| | 754 | for (int i = 0; i < fn_type_id->param_count; i += 1) { |
| | 755 | FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; |
| | 756 | TypeTableEntry *type_entry = src_param_info->type; |
| | 757 | FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; |
| | 758 | |
| | 759 | gen_param_info->src_index = i; |
| | 760 | gen_param_info->gen_index = -1; |
| | 761 | |
| | 762 | assert(type_is_complete(type_entry)); |
| | 763 | if (type_has_bits(type_entry)) { |
| | 764 | TypeTableEntry *gen_type; |
| | 765 | if (handle_is_ptr(type_entry)) { |
| | 766 | gen_type = get_pointer_to_type(g, type_entry, true); |
| | 767 | gen_param_info->is_byval = true; |
| | 768 | } else { |
| | 769 | gen_type = type_entry; |
| | 770 | } |
| | 771 | gen_param_types[gen_param_index] = gen_type->type_ref; |
| | 772 | gen_param_info->gen_index = gen_param_index; |
| | 773 | gen_param_info->type = gen_type; |
| | 774 | |
| | 775 | gen_param_index += 1; |
| 759 | | 776 | |
| 760 | fn_type->data.fn.gen_param_count = gen_param_index; | 777 | // after the gen_param_index += 1 because 0 is the return type |
| | 778 | param_di_types[gen_param_index] = gen_type->di_type; |
| | 779 | } |
| | 780 | } |
| 761 | | 781 | |
| 762 | fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, | 782 | fn_type->data.fn.gen_param_count = gen_param_index; |
| 763 | gen_param_types, gen_param_index, fn_type_id->is_var_args); | 783 | |
| 764 | fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); | 784 | fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, |
| 765 | fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, param_di_types, gen_param_index + 1, 0); | 785 | gen_param_types, gen_param_index, fn_type_id->is_var_args); |
| | 786 | fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); |
| | 787 | fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, param_di_types, gen_param_index + 1, 0); |
| | 788 | } |
| 766 | | 789 | |
| 767 | g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); | 790 | g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); |
| 768 | | 791 | |
| ... | @@ -862,8 +885,15 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -862,8 +885,15 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B |
| 862 | return analyze_type_expr_pointer_only(g, import, context, node, false); | 885 | return analyze_type_expr_pointer_only(g, import, context, node, false); |
| 863 | } | 886 | } |
| 864 | | 887 | |
| | 888 | static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) { |
| | 889 | assert(fn_table_entry); |
| | 890 | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; |
| | 891 | return fn_proto->inline_arg_count == fn_proto->params.length && fn_table_entry->want_pure == WantPureTrue; |
| | 892 | } |
| | 893 | |
| | 894 | // fn_table_entry is populated if and only if there is a function definition for this prototype |
| 865 | static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 895 | static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 866 | TypeTableEntry *expected_type, AstNode *node, bool is_naked, bool is_cold) | 896 | TypeTableEntry *expected_type, AstNode *node, bool is_naked, bool is_cold, FnTableEntry *fn_table_entry) |
| 867 | { | 897 | { |
| 868 | assert(node->type == NodeTypeFnProto); | 898 | assert(node->type == NodeTypeFnProto); |
| 869 | AstNodeFnProto *fn_proto = &node->data.fn_proto; | 899 | AstNodeFnProto *fn_proto = &node->data.fn_proto; |
| ... | @@ -876,7 +906,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor | ... | @@ -876,7 +906,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 876 | fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->top_level_decl.visib_mod == VisibModExport); | 906 | fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->top_level_decl.visib_mod == VisibModExport); |
| 877 | fn_type_id.is_naked = is_naked; | 907 | fn_type_id.is_naked = is_naked; |
| 878 | fn_type_id.is_cold = is_cold; | 908 | fn_type_id.is_cold = is_cold; |
| 879 | fn_type_id.is_inline = fn_proto->is_inline; | | |
| 880 | fn_type_id.param_count = fn_proto->params.length; | 909 | fn_type_id.param_count = fn_proto->params.length; |
| 881 | | 910 | |
| 882 | if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) { | 911 | if (fn_type_id.param_count > fn_type_id_prealloc_param_info_count) { |
| ... | @@ -902,14 +931,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor | ... | @@ -902,14 +931,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 902 | buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name))); | 931 | buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name))); |
| 903 | break; | 932 | break; |
| 904 | case TypeTableEntryIdMetaType: | 933 | case TypeTableEntryIdMetaType: |
| 905 | if (!fn_proto->is_inline) { | | |
| 906 | fn_proto->skip = true; | | |
| 907 | add_node_error(g, fn_proto->return_type, | | |
| 908 | buf_sprintf("function with return type '%s' must be declared inline", | | |
| 909 | buf_ptr(&fn_type_id.return_type->name))); | | |
| 910 | return g->builtin_types.entry_invalid; | | |
| 911 | } | | |
| 912 | break; | | |
| 913 | case TypeTableEntryIdUnreachable: | 934 | case TypeTableEntryIdUnreachable: |
| 914 | case TypeTableEntryIdVoid: | 935 | case TypeTableEntryIdVoid: |
| 915 | case TypeTableEntryIdBool: | 936 | case TypeTableEntryIdBool: |
| ... | @@ -984,7 +1005,33 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor | ... | @@ -984,7 +1005,33 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 984 | return g->builtin_types.entry_invalid; | 1005 | return g->builtin_types.entry_invalid; |
| 985 | } | 1006 | } |
| 986 | | 1007 | |
| 987 | return get_fn_type(g, &fn_type_id); | 1008 | if (fn_table_entry && fn_type_id.return_type->id == TypeTableEntryIdMetaType) { |
| | 1009 | fn_table_entry->want_pure = WantPureTrue; |
| | 1010 | fn_table_entry->want_pure_return_type = fn_proto->return_type; |
| | 1011 | |
| | 1012 | ErrorMsg *err_msg = nullptr; |
| | 1013 | for (int i = 0; i < fn_proto->params.length; i += 1) { |
| | 1014 | AstNode *param_decl_node = fn_proto->params.at(i); |
| | 1015 | assert(param_decl_node->type == NodeTypeParamDecl); |
| | 1016 | if (!param_decl_node->data.param_decl.is_inline) { |
| | 1017 | if (!err_msg) { |
| | 1018 | err_msg = add_node_error(g, fn_proto->return_type, |
| | 1019 | buf_sprintf("function with return type '%s' must declare all parameters inline", |
| | 1020 | buf_ptr(&fn_type_id.return_type->name))); |
| | 1021 | } |
| | 1022 | add_error_note(g, err_msg, param_decl_node, |
| | 1023 | buf_sprintf("non-inline parameter here")); |
| | 1024 | } |
| | 1025 | } |
| | 1026 | if (err_msg) { |
| | 1027 | fn_proto->skip = true; |
| | 1028 | return g->builtin_types.entry_invalid; |
| | 1029 | } |
| | 1030 | } |
| | 1031 | |
| | 1032 | |
| | 1033 | bool gen_debug_info = !(fn_table_entry && fn_wants_full_static_eval(fn_table_entry)); |
| | 1034 | return get_fn_type(g, &fn_type_id, gen_debug_info); |
| 988 | } | 1035 | } |
| 989 | | 1036 | |
| 990 | static Buf *resolve_const_expr_str(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode **node) { | 1037 | static Buf *resolve_const_expr_str(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode **node) { |
| ... | @@ -1110,10 +1157,12 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -1110,10 +1157,12 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 1110 | bool enable; | 1157 | bool enable; |
| 1111 | bool ok = resolve_const_expr_bool(g, import, import->block_context, | 1158 | bool ok = resolve_const_expr_bool(g, import, import->block_context, |
| 1112 | &directive_node->data.directive.expr, &enable); | 1159 | &directive_node->data.directive.expr, &enable); |
| 1113 | if (!enable || !ok) { | 1160 | if (!ok || !enable) { |
| 1114 | fn_table_entry->want_pure = WantPureFalse; | 1161 | fn_table_entry->want_pure = WantPureFalse; |
| | 1162 | } else if (ok && enable) { |
| | 1163 | fn_table_entry->want_pure = WantPureTrue; |
| | 1164 | fn_table_entry->want_pure_attr_node = directive_node->data.directive.expr; |
| 1115 | } | 1165 | } |
| 1116 | // TODO cause compile error if enable is true and impure fn | | |
| 1117 | } | 1166 | } |
| 1118 | } else { | 1167 | } else { |
| 1119 | add_node_error(g, directive_node, | 1168 | add_node_error(g, directive_node, |
| ... | @@ -1129,21 +1178,24 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -1129,21 +1178,24 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 1129 | | 1178 | |
| 1130 | | 1179 | |
| 1131 | TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, containing_context, nullptr, node, | 1180 | TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, containing_context, nullptr, node, |
| 1132 | is_naked, is_cold); | 1181 | is_naked, is_cold, fn_table_entry); |
| 1133 | | 1182 | |
| 1134 | fn_table_entry->type_entry = fn_type; | 1183 | fn_table_entry->type_entry = fn_type; |
| 1135 | fn_table_entry->is_test = is_test; | 1184 | fn_table_entry->is_test = is_test; |
| 1136 | fn_table_entry->is_noinline = is_noinline; | | |
| 1137 | | 1185 | |
| 1138 | if (fn_type->id == TypeTableEntryIdInvalid) { | 1186 | if (fn_type->id == TypeTableEntryIdInvalid) { |
| 1139 | fn_proto->skip = true; | 1187 | fn_proto->skip = true; |
| 1140 | return; | 1188 | return; |
| 1141 | } | 1189 | } |
| 1142 | | 1190 | |
| 1143 | if (fn_proto->is_inline && fn_table_entry->is_noinline) { | 1191 | if (fn_proto->is_inline && is_noinline) { |
| 1144 | add_node_error(g, node, buf_sprintf("function is both inline and noinline")); | 1192 | add_node_error(g, node, buf_sprintf("function is both inline and noinline")); |
| 1145 | fn_proto->skip = true; | 1193 | fn_proto->skip = true; |
| 1146 | return; | 1194 | return; |
| | 1195 | } else if (fn_proto->is_inline) { |
| | 1196 | fn_table_entry->fn_inline = FnInlineAlways; |
| | 1197 | } else if (is_noinline) { |
| | 1198 | fn_table_entry->fn_inline = FnInlineNever; |
| 1147 | } | 1199 | } |
| 1148 | | 1200 | |
| 1149 | | 1201 | |
| ... | @@ -1159,48 +1211,54 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -1159,48 +1211,54 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 1159 | fn_table_entry->fn_def_node->data.fn_def.block_context = context; | 1211 | fn_table_entry->fn_def_node->data.fn_def.block_context = context; |
| 1160 | } | 1212 | } |
| 1161 | | 1213 | |
| 1162 | fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref); | 1214 | if (!fn_wants_full_static_eval(fn_table_entry)) { |
| 1163 | | 1215 | fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref); |
| 1164 | if (fn_proto->is_inline) { | | |
| 1165 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute); | | |
| 1166 | } | | |
| 1167 | if (fn_table_entry->is_noinline) { | | |
| 1168 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoInlineAttribute); | | |
| 1169 | } | | |
| 1170 | if (fn_type->data.fn.fn_type_id.is_naked) { | | |
| 1171 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute); | | |
| 1172 | } | | |
| 1173 | | 1216 | |
| 1174 | LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ? | 1217 | switch (fn_table_entry->fn_inline) { |
| 1175 | LLVMInternalLinkage : LLVMExternalLinkage); | 1218 | case FnInlineAlways: |
| | 1219 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute); |
| | 1220 | break; |
| | 1221 | case FnInlineNever: |
| | 1222 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoInlineAttribute); |
| | 1223 | break; |
| | 1224 | case FnInlineAuto: |
| | 1225 | break; |
| | 1226 | } |
| | 1227 | if (fn_type->data.fn.fn_type_id.is_naked) { |
| | 1228 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute); |
| | 1229 | } |
| 1176 | | 1230 | |
| 1177 | if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { | 1231 | LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ? |
| 1178 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute); | 1232 | LLVMInternalLinkage : LLVMExternalLinkage); |
| 1179 | } | | |
| 1180 | LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention); | | |
| 1181 | if (!fn_table_entry->is_extern) { | | |
| 1182 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute); | | |
| 1183 | } | | |
| 1184 | if (!g->is_release_build && !fn_proto->is_inline) { | | |
| 1185 | ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim", "true"); | | |
| 1186 | ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim-non-leaf", nullptr); | | |
| 1187 | } | | |
| 1188 | | 1233 | |
| 1189 | if (fn_table_entry->fn_def_node) { | 1234 | if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { |
| 1190 | // Add debug info. | 1235 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute); |
| 1191 | unsigned line_number = node->line + 1; | 1236 | } |
| 1192 | unsigned scope_line = line_number; | 1237 | LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention); |
| 1193 | bool is_definition = fn_table_entry->fn_def_node != nullptr; | 1238 | if (!fn_table_entry->is_extern) { |
| 1194 | unsigned flags = 0; | 1239 | LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute); |
| 1195 | bool is_optimized = g->is_release_build; | 1240 | } |
| 1196 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, | 1241 | if (!g->is_release_build && !fn_proto->is_inline) { |
| 1197 | containing_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "", | 1242 | ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim", "true"); |
| 1198 | import->di_file, line_number, | 1243 | ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim-non-leaf", nullptr); |
| 1199 | fn_type->di_type, fn_table_entry->internal_linkage, | 1244 | } |
| 1200 | is_definition, scope_line, flags, is_optimized, nullptr); | | |
| 1201 | | 1245 | |
| 1202 | fn_table_entry->fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram); | 1246 | if (fn_table_entry->fn_def_node) { |
| 1203 | ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram); | 1247 | // Add debug info. |
| | 1248 | unsigned line_number = node->line + 1; |
| | 1249 | unsigned scope_line = line_number; |
| | 1250 | bool is_definition = fn_table_entry->fn_def_node != nullptr; |
| | 1251 | unsigned flags = 0; |
| | 1252 | bool is_optimized = g->is_release_build; |
| | 1253 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, |
| | 1254 | containing_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "", |
| | 1255 | import->di_file, line_number, |
| | 1256 | fn_type->di_type, fn_table_entry->internal_linkage, |
| | 1257 | is_definition, scope_line, flags, is_optimized, nullptr); |
| | 1258 | |
| | 1259 | fn_table_entry->fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram); |
| | 1260 | ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram); |
| | 1261 | } |
| 1204 | } | 1262 | } |
| 1205 | } | 1263 | } |
| 1206 | | 1264 | |
| ... | @@ -1609,29 +1667,31 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN | ... | @@ -1609,29 +1667,31 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN |
| 1609 | | 1667 | |
| 1610 | | 1668 | |
| 1611 | } else { | 1669 | } else { |
| 1612 | g->fn_protos.append(fn_table_entry); | 1670 | resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context); |
| 1613 | | 1671 | |
| 1614 | if (fn_def_node) { | 1672 | if (!fn_wants_full_static_eval(fn_table_entry)) { |
| 1615 | g->fn_defs.append(fn_table_entry); | 1673 | g->fn_protos.append(fn_table_entry); |
| 1616 | } | | |
| 1617 | | 1674 | |
| 1618 | bool is_main_fn = !is_generic_instance && | 1675 | if (fn_def_node) { |
| 1619 | !parent_decl && (import == g->root_import) && | 1676 | g->fn_defs.append(fn_table_entry); |
| 1620 | buf_eql_str(proto_name, "main"); | 1677 | } |
| 1621 | if (is_main_fn) { | | |
| 1622 | g->main_fn = fn_table_entry; | | |
| 1623 | } | | |
| 1624 | | 1678 | |
| 1625 | resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context); | 1679 | bool is_main_fn = !is_generic_instance && |
| | 1680 | !parent_decl && (import == g->root_import) && |
| | 1681 | buf_eql_str(proto_name, "main"); |
| | 1682 | if (is_main_fn) { |
| | 1683 | g->main_fn = fn_table_entry; |
| | 1684 | } |
| 1626 | | 1685 | |
| 1627 | if (is_main_fn && !g->link_libc) { | 1686 | if (is_main_fn && !g->link_libc) { |
| 1628 | TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); | 1687 | TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); |
| 1629 | TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; | 1688 | TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; |
| 1630 | if (actual_return_type != err_void) { | 1689 | if (actual_return_type != err_void) { |
| 1631 | AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type; | 1690 | AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type; |
| 1632 | add_node_error(g, return_type_node, | 1691 | add_node_error(g, return_type_node, |
| 1633 | buf_sprintf("expected return type of main to be '%%void', instead is '%s'", | 1692 | buf_sprintf("expected return type of main to be '%%void', instead is '%s'", |
| 1634 | buf_ptr(&actual_return_type->name))); | 1693 | buf_ptr(&actual_return_type->name))); |
| | 1694 | } |
| 1635 | } | 1695 | } |
| 1636 | } | 1696 | } |
| 1637 | } | 1697 | } |
| ... | @@ -3022,7 +3082,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl | ... | @@ -3022,7 +3082,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl |
| 3022 | { | 3082 | { |
| 3023 | get_resolved_expr(source_node)->variable = var; | 3083 | get_resolved_expr(source_node)->variable = var; |
| 3024 | if (!var_is_pure(var, context)) { | 3084 | if (!var_is_pure(var, context)) { |
| 3025 | mark_impure_fn(context); | 3085 | mark_impure_fn(g, context, source_node); |
| 3026 | } | 3086 | } |
| 3027 | if (var->is_const && var->val_node) { | 3087 | if (var->is_const && var->val_node) { |
| 3028 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; | 3088 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; |
| ... | @@ -3102,7 +3162,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -3102,7 +3162,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 3102 | return g->builtin_types.entry_invalid; | 3162 | return g->builtin_types.entry_invalid; |
| 3103 | } | 3163 | } |
| 3104 | | 3164 | |
| 3105 | mark_impure_fn(context); | 3165 | mark_impure_fn(g, context, node); |
| 3106 | add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); | 3166 | add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); |
| 3107 | return g->builtin_types.entry_invalid; | 3167 | return g->builtin_types.entry_invalid; |
| 3108 | } | 3168 | } |
| ... | @@ -3943,7 +4003,8 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, | ... | @@ -3943,7 +4003,8 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, |
| 3943 | static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 4003 | static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 3944 | TypeTableEntry *expected_type, AstNode *node) | 4004 | TypeTableEntry *expected_type, AstNode *node) |
| 3945 | { | 4005 | { |
| 3946 | TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, false, false); | 4006 | TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, |
| | 4007 | false, false, nullptr); |
| 3947 | | 4008 | |
| 3948 | if (type_entry->id == TypeTableEntryIdInvalid) { | 4009 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 3949 | return type_entry; | 4010 | return type_entry; |
| ... | @@ -4386,7 +4447,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -4386,7 +4447,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 4386 | (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const || | 4447 | (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const || |
| 4387 | !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const)) | 4448 | !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const)) |
| 4388 | { | 4449 | { |
| 4389 | mark_impure_fn(context); | 4450 | mark_impure_fn(g, context, node); |
| 4390 | return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true); | 4451 | return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true); |
| 4391 | } | 4452 | } |
| 4392 | | 4453 | |
| ... | @@ -4395,7 +4456,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -4395,7 +4456,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 4395 | actual_type->id == TypeTableEntryIdArray && | 4456 | actual_type->id == TypeTableEntryIdArray && |
| 4396 | is_u8(actual_type->data.array.child_type)) | 4457 | is_u8(actual_type->data.array.child_type)) |
| 4397 | { | 4458 | { |
| 4398 | mark_impure_fn(context); | 4459 | mark_impure_fn(g, context, node); |
| 4399 | uint64_t child_type_size = type_size(g, | 4460 | uint64_t child_type_size = type_size(g, |
| 4400 | wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type); | 4461 | wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type); |
| 4401 | if (actual_type->data.array.len % child_type_size == 0) { | 4462 | if (actual_type->data.array.len % child_type_size == 0) { |
| ... | @@ -5276,11 +5337,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry | ... | @@ -5276,11 +5337,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 5276 | case BuiltinFnIdErrName: | 5337 | case BuiltinFnIdErrName: |
| 5277 | return analyze_err_name(g, import, context, node); | 5338 | return analyze_err_name(g, import, context, node); |
| 5278 | case BuiltinFnIdBreakpoint: | 5339 | case BuiltinFnIdBreakpoint: |
| 5279 | mark_impure_fn(context); | 5340 | mark_impure_fn(g, context, node); |
| 5280 | return g->builtin_types.entry_void; | 5341 | return g->builtin_types.entry_void; |
| 5281 | case BuiltinFnIdReturnAddress: | 5342 | case BuiltinFnIdReturnAddress: |
| 5282 | case BuiltinFnIdFrameAddress: | 5343 | case BuiltinFnIdFrameAddress: |
| 5283 | mark_impure_fn(context); | 5344 | mark_impure_fn(g, context, node); |
| 5284 | return builtin_fn->return_type; | 5345 | return builtin_fn->return_type; |
| 5285 | case BuiltinFnIdEmbedFile: | 5346 | case BuiltinFnIdEmbedFile: |
| 5286 | return analyze_embed_file(g, import, context, node); | 5347 | return analyze_embed_file(g, import, context, node); |
| ... | @@ -5388,6 +5449,9 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, | ... | @@ -5388,6 +5449,9 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 5388 | if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) { | 5449 | if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) { |
| 5389 | if (fn_table_entry->anal_state == FnAnalStateReady) { | 5450 | if (fn_table_entry->anal_state == FnAnalStateReady) { |
| 5390 | analyze_fn_body(g, fn_table_entry); | 5451 | analyze_fn_body(g, fn_table_entry); |
| | 5452 | if (fn_table_entry->proto_node->data.fn_proto.skip) { |
| | 5453 | return g->builtin_types.entry_invalid; |
| | 5454 | } |
| 5391 | } | 5455 | } |
| 5392 | if (all_args_const_expr) { | 5456 | if (all_args_const_expr) { |
| 5393 | if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) { | 5457 | if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) { |
| ... | @@ -5401,7 +5465,10 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, | ... | @@ -5401,7 +5465,10 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 5401 | } | 5465 | } |
| 5402 | if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure || fn_table_entry->want_pure == WantPureFalse) { | 5466 | if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure || fn_table_entry->want_pure == WantPureFalse) { |
| 5403 | // calling an impure fn is impure | 5467 | // calling an impure fn is impure |
| 5404 | mark_impure_fn(context); | 5468 | mark_impure_fn(g, context, node); |
| | 5469 | if (fn_table_entry && fn_table_entry->want_pure == WantPureTrue) { |
| | 5470 | return g->builtin_types.entry_invalid; |
| | 5471 | } |
| 5405 | } | 5472 | } |
| 5406 | | 5473 | |
| 5407 | if (handle_is_ptr(return_type)) { | 5474 | if (handle_is_ptr(return_type)) { |
| ... | @@ -6298,7 +6365,7 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -6298,7 +6365,7 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, |
| 6298 | static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 6365 | static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 6299 | TypeTableEntry *expected_type, AstNode *node) | 6366 | TypeTableEntry *expected_type, AstNode *node) |
| 6300 | { | 6367 | { |
| 6301 | mark_impure_fn(context); | 6368 | mark_impure_fn(g, context, node); |
| 6302 | | 6369 | |
| 6303 | node->data.asm_expr.return_count = 0; | 6370 | node->data.asm_expr.return_count = 0; |
| 6304 | TypeTableEntry *return_type = g->builtin_types.entry_void; | 6371 | TypeTableEntry *return_type = g->builtin_types.entry_void; |