| ... | @@ -1731,7 +1731,13 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o | ... | @@ -1731,7 +1731,13 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o |
| 1731 | } | 1731 | } |
| 1732 | } | 1732 | } |
| 1733 | | 1733 | |
| 1734 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) { | 1734 | static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { |
| | 1735 | assert(basic_block); |
| | 1736 | |
| | 1737 | irb->current_basic_block = basic_block; |
| | 1738 | } |
| | 1739 | |
| | 1740 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { |
| 1735 | assert(node->type == NodeTypeReturnExpr); | 1741 | assert(node->type == NodeTypeReturnExpr); |
| 1736 | | 1742 | |
| 1737 | FnTableEntry *fn_entry = exec_fn_entry(irb->exec); | 1743 | FnTableEntry *fn_entry = exec_fn_entry(irb->exec); |
| ... | @@ -1740,6 +1746,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -1740,6 +1746,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) |
| 1740 | return irb->codegen->invalid_instruction; | 1746 | return irb->codegen->invalid_instruction; |
| 1741 | } | 1747 | } |
| 1742 | | 1748 | |
| | 1749 | Scope *outer_scope = fn_entry->child_scope; |
| | 1750 | bool is_inline = ir_should_inline(irb); |
| | 1751 | |
| 1743 | AstNode *expr_node = node->data.return_expr.expr; | 1752 | AstNode *expr_node = node->data.return_expr.expr; |
| 1744 | switch (node->data.return_expr.kind) { | 1753 | switch (node->data.return_expr.kind) { |
| 1745 | case ReturnKindUnconditional: | 1754 | case ReturnKindUnconditional: |
| ... | @@ -1747,28 +1756,46 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -1747,28 +1756,46 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) |
| 1747 | IrInstruction *return_value; | 1756 | IrInstruction *return_value; |
| 1748 | if (expr_node) { | 1757 | if (expr_node) { |
| 1749 | return_value = ir_gen_node(irb, expr_node, scope); | 1758 | return_value = ir_gen_node(irb, expr_node, scope); |
| | 1759 | if (return_value == irb->codegen->invalid_instruction) |
| | 1760 | return irb->codegen->invalid_instruction; |
| 1750 | } else { | 1761 | } else { |
| 1751 | return_value = ir_build_const_void(irb, scope, node); | 1762 | return_value = ir_build_const_void(irb, scope, node); |
| 1752 | } | 1763 | } |
| 1753 | | 1764 | |
| 1754 | Scope *outer_scope = fn_entry->child_scope; | 1765 | // TODO conditionally gen maybe defers and error defers |
| 1755 | ir_gen_defers_for_block(irb, scope, outer_scope, false, false); | 1766 | ir_gen_defers_for_block(irb, scope, outer_scope, false, false); |
| 1756 | return ir_build_return(irb, scope, node, return_value); | 1767 | return ir_build_return(irb, scope, node, return_value); |
| 1757 | } | 1768 | } |
| 1758 | case ReturnKindError: | 1769 | case ReturnKindError: |
| 1759 | zig_panic("TODO gen IR for %%return"); | 1770 | zig_panic("TODO gen IR for %%return"); |
| 1760 | case ReturnKindMaybe: | 1771 | case ReturnKindMaybe: |
| 1761 | zig_panic("TODO gen IR for ?return"); | 1772 | { |
| | 1773 | assert(expr_node); |
| | 1774 | IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); |
| | 1775 | if (maybe_val_ptr == irb->codegen->invalid_instruction) |
| | 1776 | return irb->codegen->invalid_instruction; |
| | 1777 | IrInstruction *is_nonnull_val = ir_build_test_null(irb, scope, node, maybe_val_ptr); |
| | 1778 | |
| | 1779 | IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn"); |
| | 1780 | IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue"); |
| | 1781 | ir_build_cond_br(irb, scope, node, is_nonnull_val, continue_block, return_block, is_inline); |
| | 1782 | |
| | 1783 | ir_set_cursor_at_end(irb, return_block); |
| | 1784 | ir_gen_defers_for_block(irb, scope, outer_scope, false, true); |
| | 1785 | IrInstruction *null = ir_build_const_null(irb, scope, node); |
| | 1786 | ir_build_return(irb, scope, node, null); |
| | 1787 | |
| | 1788 | ir_set_cursor_at_end(irb, continue_block); |
| | 1789 | IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_val_ptr, false); |
| | 1790 | if (lval != LValPurposeNone) |
| | 1791 | return unwrapped_ptr; |
| | 1792 | else |
| | 1793 | return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); |
| | 1794 | } |
| 1762 | } | 1795 | } |
| 1763 | zig_unreachable(); | 1796 | zig_unreachable(); |
| 1764 | } | 1797 | } |
| 1765 | | 1798 | |
| 1766 | static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { | | |
| 1767 | assert(basic_block); | | |
| 1768 | | | |
| 1769 | irb->current_basic_block = basic_block; | | |
| 1770 | } | | |
| 1771 | | | |
| 1772 | static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, | 1799 | static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, |
| 1773 | Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, bool is_inline) | 1800 | Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, bool is_inline) |
| 1774 | { | 1801 | { |
| ... | @@ -3606,7 +3633,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -3606,7 +3633,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 3606 | case NodeTypeArrayAccessExpr: | 3633 | case NodeTypeArrayAccessExpr: |
| 3607 | return ir_gen_array_access(irb, scope, node, lval); | 3634 | return ir_gen_array_access(irb, scope, node, lval); |
| 3608 | case NodeTypeReturnExpr: | 3635 | case NodeTypeReturnExpr: |
| 3609 | return ir_lval_wrap(irb, scope, ir_gen_return(irb, scope, node), lval); | 3636 | return ir_gen_return(irb, scope, node, lval); |
| 3610 | case NodeTypeFieldAccessExpr: | 3637 | case NodeTypeFieldAccessExpr: |
| 3611 | return ir_gen_field_access(irb, scope, node, lval); | 3638 | return ir_gen_field_access(irb, scope, node, lval); |
| 3612 | case NodeTypeThisLiteral: | 3639 | case NodeTypeThisLiteral: |
| ... | @@ -3827,6 +3854,7 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n | ... | @@ -3827,6 +3854,7 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n |
| 3827 | return ira->codegen->builtin_types.entry_invalid; | 3854 | return ira->codegen->builtin_types.entry_invalid; |
| 3828 | } | 3855 | } |
| 3829 | bool any_are_pure_error = (prev_inst->type_entry->id == TypeTableEntryIdPureError); | 3856 | bool any_are_pure_error = (prev_inst->type_entry->id == TypeTableEntryIdPureError); |
| | 3857 | bool any_are_null = (prev_inst->type_entry->id == TypeTableEntryIdNullLit); |
| 3830 | for (size_t i = 1; i < instruction_count; i += 1) { | 3858 | for (size_t i = 1; i < instruction_count; i += 1) { |
| 3831 | IrInstruction *cur_inst = instructions[i]; | 3859 | IrInstruction *cur_inst = instructions[i]; |
| 3832 | TypeTableEntry *cur_type = cur_inst->type_entry; | 3860 | TypeTableEntry *cur_type = cur_inst->type_entry; |
| ... | @@ -3836,9 +3864,15 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n | ... | @@ -3836,9 +3864,15 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n |
| 3836 | } else if (prev_type->id == TypeTableEntryIdPureError) { | 3864 | } else if (prev_type->id == TypeTableEntryIdPureError) { |
| 3837 | prev_inst = cur_inst; | 3865 | prev_inst = cur_inst; |
| 3838 | continue; | 3866 | continue; |
| | 3867 | } else if (prev_type->id == TypeTableEntryIdNullLit) { |
| | 3868 | prev_inst = cur_inst; |
| | 3869 | continue; |
| 3839 | } else if (cur_type->id == TypeTableEntryIdPureError) { | 3870 | } else if (cur_type->id == TypeTableEntryIdPureError) { |
| 3840 | any_are_pure_error = true; | 3871 | any_are_pure_error = true; |
| 3841 | continue; | 3872 | continue; |
| | 3873 | } else if (cur_type->id == TypeTableEntryIdNullLit) { |
| | 3874 | any_are_null = true; |
| | 3875 | continue; |
| 3842 | } else if (types_match_const_cast_only(prev_type, cur_type)) { | 3876 | } else if (types_match_const_cast_only(prev_type, cur_type)) { |
| 3843 | continue; | 3877 | continue; |
| 3844 | } else if (types_match_const_cast_only(cur_type, prev_type)) { | 3878 | } else if (types_match_const_cast_only(cur_type, prev_type)) { |
| ... | @@ -3889,9 +3923,13 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n | ... | @@ -3889,9 +3923,13 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n |
| 3889 | return ira->codegen->builtin_types.entry_invalid; | 3923 | return ira->codegen->builtin_types.entry_invalid; |
| 3890 | } | 3924 | } |
| 3891 | } else { | 3925 | } else { |
| 3892 | add_node_error(ira->codegen, source_node, | 3926 | ErrorMsg *msg = add_node_error(ira->codegen, source_node, |
| 3893 | buf_sprintf("incompatible types: '%s' and '%s'", | 3927 | buf_sprintf("incompatible types: '%s' and '%s'", |
| 3894 | buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); | 3928 | buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); |
| | 3929 | add_error_note(ira->codegen, msg, prev_inst->source_node, |
| | 3930 | buf_sprintf("type '%s' here", buf_ptr(&prev_type->name))); |
| | 3931 | add_error_note(ira->codegen, msg, cur_inst->source_node, |
| | 3932 | buf_sprintf("type '%s' here", buf_ptr(&cur_type->name))); |
| 3895 | | 3933 | |
| 3896 | return ira->codegen->builtin_types.entry_invalid; | 3934 | return ira->codegen->builtin_types.entry_invalid; |
| 3897 | } | 3935 | } |
| ... | @@ -3903,9 +3941,23 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n | ... | @@ -3903,9 +3941,23 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n |
| 3903 | add_node_error(ira->codegen, source_node, | 3941 | add_node_error(ira->codegen, source_node, |
| 3904 | buf_sprintf("unable to make error union out of number literal")); | 3942 | buf_sprintf("unable to make error union out of number literal")); |
| 3905 | return ira->codegen->builtin_types.entry_invalid; | 3943 | return ira->codegen->builtin_types.entry_invalid; |
| | 3944 | } else if (prev_inst->type_entry->id == TypeTableEntryIdNullLit) { |
| | 3945 | add_node_error(ira->codegen, source_node, |
| | 3946 | buf_sprintf("unable to make error union out of null literal")); |
| | 3947 | return ira->codegen->builtin_types.entry_invalid; |
| 3906 | } else { | 3948 | } else { |
| 3907 | return get_error_type(ira->codegen, prev_inst->type_entry); | 3949 | return get_error_type(ira->codegen, prev_inst->type_entry); |
| 3908 | } | 3950 | } |
| | 3951 | } else if (any_are_null && prev_inst->type_entry->id != TypeTableEntryIdNullLit) { |
| | 3952 | if (prev_inst->type_entry->id == TypeTableEntryIdNumLitInt || |
| | 3953 | prev_inst->type_entry->id == TypeTableEntryIdNumLitFloat) |
| | 3954 | { |
| | 3955 | add_node_error(ira->codegen, source_node, |
| | 3956 | buf_sprintf("unable to make maybe out of number literal")); |
| | 3957 | return ira->codegen->builtin_types.entry_invalid; |
| | 3958 | } else { |
| | 3959 | return get_maybe_type(ira->codegen, prev_inst->type_entry); |
| | 3960 | } |
| 3909 | } else { | 3961 | } else { |
| 3910 | return prev_inst->type_entry; | 3962 | return prev_inst->type_entry; |
| 3911 | } | 3963 | } |
| ... | @@ -9053,16 +9105,9 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -9053,16 +9105,9 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 9053 | //static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 9105 | //static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 9054 | // TypeTableEntry *expected_type, AstNode *node) | 9106 | // TypeTableEntry *expected_type, AstNode *node) |
| 9055 | //{ | 9107 | //{ |
| 9056 | // if (!node->data.return_expr.expr) { | | |
| 9057 | // node->data.return_expr.expr = create_ast_void_node(g, import, node); | | |
| 9058 | // normalize_parent_ptrs(node); | | |
| 9059 | // } | | |
| 9060 | // | | |
| 9061 | // TypeTableEntry *expected_return_type = get_return_type(context); | 9108 | // TypeTableEntry *expected_return_type = get_return_type(context); |
| 9062 | // | 9109 | // |
| 9063 | // switch (node->data.return_expr.kind) { | 9110 | // switch (node->data.return_expr.kind) { |
| 9064 | // case ReturnKindUnconditional: | | |
| 9065 | // zig_panic("TODO moved to ir.cpp"); | | |
| 9066 | // case ReturnKindError: | 9111 | // case ReturnKindError: |
| 9067 | // { | 9112 | // { |
| 9068 | // TypeTableEntry *expected_err_type; | 9113 | // TypeTableEntry *expected_err_type; |
| ... | @@ -9093,34 +9138,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -9093,34 +9138,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 9093 | // return g->builtin_types.entry_invalid; | 9138 | // return g->builtin_types.entry_invalid; |
| 9094 | // } | 9139 | // } |
| 9095 | // } | 9140 | // } |
| 9096 | // case ReturnKindMaybe: | | |
| 9097 | // { | | |
| 9098 | // TypeTableEntry *expected_maybe_type; | | |
| 9099 | // if (expected_type) { | | |
| 9100 | // expected_maybe_type = get_maybe_type(g, expected_type); | | |
| 9101 | // } else { | | |
| 9102 | // expected_maybe_type = nullptr; | | |
| 9103 | // } | | |
| 9104 | // TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_maybe_type, | | |
| 9105 | // node->data.return_expr.expr); | | |
| 9106 | // if (resolved_type->id == TypeTableEntryIdInvalid) { | | |
| 9107 | // return resolved_type; | | |
| 9108 | // } else if (resolved_type->id == TypeTableEntryIdMaybe) { | | |
| 9109 | // if (expected_return_type->id != TypeTableEntryIdMaybe) { | | |
| 9110 | // ErrorMsg *msg = add_node_error(g, node, | | |
| 9111 | // buf_sprintf("?return statement in function with return type '%s'", | | |
| 9112 | // buf_ptr(&expected_return_type->name))); | | |
| 9113 | // AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type; | | |
| 9114 | // add_error_note(g, msg, return_type_node, buf_sprintf("function return type here")); | | |
| 9115 | // } | | |
| 9116 | // | | |
| 9117 | // return resolved_type->data.maybe.child_type; | | |
| 9118 | // } else { | | |
| 9119 | // add_node_error(g, node->data.return_expr.expr, | | |
| 9120 | // buf_sprintf("expected maybe type, found '%s'", buf_ptr(&resolved_type->name))); | | |
| 9121 | // return g->builtin_types.entry_invalid; | | |
| 9122 | // } | | |
| 9123 | // } | | |
| 9124 | // } | 9141 | // } |
| 9125 | // zig_unreachable(); | 9142 | // zig_unreachable(); |
| 9126 | //} | 9143 | //} |
| ... | @@ -9344,43 +9361,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -9344,43 +9361,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 9344 | // return nullptr; | 9361 | // return nullptr; |
| 9345 | // } | 9362 | // } |
| 9346 | // } | 9363 | // } |
| 9347 | // case ReturnKindMaybe: | | |
| 9348 | // { | | |
| 9349 | // assert(value_type->id == TypeTableEntryIdMaybe); | | |
| 9350 | // TypeTableEntry *child_type = value_type->data.maybe.child_type; | | |
| 9351 | // | | |
| 9352 | // LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetReturn"); | | |
| 9353 | // LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetContinue"); | | |
| 9354 | // | | |
| 9355 | // LLVMValueRef maybe_val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); | | |
| 9356 | // LLVMValueRef is_non_null = LLVMBuildLoad(g->builder, maybe_val_ptr, ""); | | |
| 9357 | // | | |
| 9358 | // LLVMValueRef zero = LLVMConstNull(LLVMInt1Type()); | | |
| 9359 | // LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntNE, is_non_null, zero, ""); | | |
| 9360 | // LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block); | | |
| 9361 | // | | |
| 9362 | // LLVMPositionBuilderAtEnd(g->builder, return_block); | | |
| 9363 | // TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; | | |
| 9364 | // assert(return_type->id == TypeTableEntryIdMaybe); | | |
| 9365 | // if (handle_is_ptr(return_type)) { | | |
| 9366 | // assert(g->cur_ret_ptr); | | |
| 9367 | // | | |
| 9368 | // LLVMValueRef maybe_bit_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 1, ""); | | |
| 9369 | // LLVMBuildStore(g->builder, zero, maybe_bit_ptr); | | |
| 9370 | // LLVMBuildRetVoid(g->builder); | | |
| 9371 | // } else { | | |
| 9372 | // LLVMValueRef ret_zero_value = LLVMConstNull(return_type->type_ref); | | |
| 9373 | // gen_return(g, node, ret_zero_value, ReturnKnowledgeKnownNull); | | |
| 9374 | // } | | |
| 9375 | // | | |
| 9376 | // LLVMPositionBuilderAtEnd(g->builder, continue_block); | | |
| 9377 | // if (type_has_bits(child_type)) { | | |
| 9378 | // LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 0, ""); | | |
| 9379 | // return get_handle_value(g, val_ptr, child_type); | | |
| 9380 | // } else { | | |
| 9381 | // return nullptr; | | |
| 9382 | // } | | |
| 9383 | // } | | |
| 9384 | // } | 9364 | // } |
| 9385 | // zig_unreachable(); | 9365 | // zig_unreachable(); |
| 9386 | //} | 9366 | //} |