| ... | @@ -663,11 +663,27 @@ fn varDecl( | ... | @@ -663,11 +663,27 @@ fn varDecl( |
| 663 | | 663 | |
| 664 | switch (tree.token_ids[node.mut_token]) { | 664 | switch (tree.token_ids[node.mut_token]) { |
| 665 | .Keyword_const => { | 665 | .Keyword_const => { |
| 666 | var resolve_inferred_alloc: ?*zir.Inst = null; | | |
| 667 | // Depending on the type of AST the initialization expression is, we may need an lvalue | 666 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| 668 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as | 667 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as |
| 669 | // the variable, no memory location needed. | 668 | // the variable, no memory location needed. |
| 670 | const result_loc = if (nodeMayNeedMemoryLocation(init_node, scope)) r: { | 669 | if (!nodeMayNeedMemoryLocation(init_node, scope)) { |
| | 670 | const result_loc: ResultLoc = if (node.getTypeNode()) |type_node| |
| | 671 | .{ .ty = try typeExpr(mod, scope, type_node) } |
| | 672 | else |
| | 673 | .none; |
| | 674 | const init_inst = try expr(mod, scope, result_loc, init_node); |
| | 675 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| | 676 | sub_scope.* = .{ |
| | 677 | .parent = scope, |
| | 678 | .gen_zir = scope.getGenZIR(), |
| | 679 | .name = ident_name, |
| | 680 | .inst = init_inst, |
| | 681 | }; |
| | 682 | return &sub_scope.base; |
| | 683 | } |
| | 684 | |
| | 685 | var resolve_inferred_alloc: ?*zir.Inst = null; |
| | 686 | const result_loc = r: { |
| 671 | if (node.getTypeNode()) |type_node| { | 687 | if (node.getTypeNode()) |type_node| { |
| 672 | const type_inst = try typeExpr(mod, scope, type_node); | 688 | const type_inst = try typeExpr(mod, scope, type_node); |
| 673 | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); | 689 | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); |
| ... | @@ -677,11 +693,6 @@ fn varDecl( | ... | @@ -677,11 +693,6 @@ fn varDecl( |
| 677 | resolve_inferred_alloc = &alloc.base; | 693 | resolve_inferred_alloc = &alloc.base; |
| 678 | break :r ResultLoc{ .inferred_ptr = alloc }; | 694 | break :r ResultLoc{ .inferred_ptr = alloc }; |
| 679 | } | 695 | } |
| 680 | } else r: { | | |
| 681 | if (node.getTypeNode()) |type_node| | | |
| 682 | break :r ResultLoc{ .ty = try typeExpr(mod, scope, type_node) } | | |
| 683 | else | | |
| 684 | break :r .none; | | |
| 685 | }; | 696 | }; |
| 686 | const init_inst = try expr(mod, scope, result_loc, init_node); | 697 | const init_inst = try expr(mod, scope, result_loc, init_node); |
| 687 | if (resolve_inferred_alloc) |inst| { | 698 | if (resolve_inferred_alloc) |inst| { |
| ... | @@ -1718,14 +1729,20 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn | ... | @@ -1718,14 +1729,20 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1718 | switch (strategy) { | 1729 | switch (strategy) { |
| 1719 | .break_void => { | 1730 | .break_void => { |
| 1720 | if (!then_result.tag.isNoReturn()) { | 1731 | if (!then_result.tag.isNoReturn()) { |
| 1721 | _ = try addZIRNoOp(mod, then_sub_scope, then_src, .break_void); | 1732 | _ = try addZirInstTag(mod, then_sub_scope, then_src, .break_void, .{ |
| | 1733 | .block = block, |
| | 1734 | }); |
| 1722 | } | 1735 | } |
| 1723 | if (else_result) |inst| { | 1736 | if (else_result) |inst| { |
| 1724 | if (!inst.tag.isNoReturn()) { | 1737 | if (!inst.tag.isNoReturn()) { |
| 1725 | _ = try addZIRNoOp(mod, else_sub_scope, else_src, .break_void); | 1738 | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ |
| | 1739 | .block = block, |
| | 1740 | }); |
| 1726 | } | 1741 | } |
| 1727 | } else { | 1742 | } else { |
| 1728 | _ = try addZIRNoOp(mod, else_sub_scope, else_src, .break_void); | 1743 | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ |
| | 1744 | .block = block, |
| | 1745 | }); |
| 1729 | } | 1746 | } |
| 1730 | assert(!elide_store_to_block_ptr_instructions); | 1747 | assert(!elide_store_to_block_ptr_instructions); |
| 1731 | try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); | 1748 | try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); |
| ... | @@ -1747,7 +1764,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn | ... | @@ -1747,7 +1764,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1747 | }); | 1764 | }); |
| 1748 | } | 1765 | } |
| 1749 | } else { | 1766 | } else { |
| 1750 | _ = try addZIRNoOp(mod, else_sub_scope, else_src, .break_void); | 1767 | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ |
| | 1768 | .block = block, |
| | 1769 | }); |
| 1751 | } | 1770 | } |
| 1752 | if (elide_store_to_block_ptr_instructions) { | 1771 | if (elide_store_to_block_ptr_instructions) { |
| 1753 | try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.then_body, then_scope); | 1772 | try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.then_body, then_scope); |
| ... | @@ -2728,31 +2747,30 @@ fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError | ... | @@ -2728,31 +2747,30 @@ fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError |
| 2728 | return addZIRUnOp(mod, scope, src, .ptrtoint, operand); | 2747 | return addZIRUnOp(mod, scope, src, .ptrtoint, operand); |
| 2729 | } | 2748 | } |
| 2730 | | 2749 | |
| 2731 | fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { | 2750 | fn as( |
| | 2751 | mod: *Module, |
| | 2752 | scope: *Scope, |
| | 2753 | rl: ResultLoc, |
| | 2754 | call: *ast.Node.BuiltinCall, |
| | 2755 | ) InnerError!*zir.Inst { |
| 2732 | try ensureBuiltinParamCount(mod, scope, call, 2); | 2756 | try ensureBuiltinParamCount(mod, scope, call, 2); |
| 2733 | const tree = scope.tree(); | 2757 | const tree = scope.tree(); |
| 2734 | const src = tree.token_locs[call.builtin_token].start; | 2758 | const src = tree.token_locs[call.builtin_token].start; |
| 2735 | const params = call.params(); | 2759 | const params = call.params(); |
| 2736 | const dest_type = try typeExpr(mod, scope, params[0]); | 2760 | const dest_type = try typeExpr(mod, scope, params[0]); |
| 2737 | switch (rl) { | 2761 | switch (rl) { |
| 2738 | .none => return try expr(mod, scope, .{ .ty = dest_type }, params[1]), | 2762 | .none, .discard, .ref, .ty => { |
| 2739 | .discard => { | | |
| 2740 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); | 2763 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); |
| 2741 | _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result); | 2764 | return rvalue(mod, scope, rl, result); |
| 2742 | return result; | | |
| 2743 | }, | | |
| 2744 | .ref => { | | |
| 2745 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); | | |
| 2746 | return addZIRUnOp(mod, scope, result.src, .ref, result); | | |
| 2747 | }, | | |
| 2748 | .ty => |result_ty| { | | |
| 2749 | const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]); | | |
| 2750 | return addZIRBinOp(mod, scope, src, .as, result_ty, result); | | |
| 2751 | }, | 2765 | }, |
| | 2766 | |
| 2752 | .ptr => |result_ptr| { | 2767 | .ptr => |result_ptr| { |
| 2753 | const casted_result_ptr = try addZIRBinOp(mod, scope, src, .coerce_result_ptr, dest_type, result_ptr); | 2768 | return asRlPtr(mod, scope, rl, src, result_ptr, params[1], dest_type); |
| 2754 | return expr(mod, scope, .{ .ptr = casted_result_ptr }, params[1]); | | |
| 2755 | }, | 2769 | }, |
| | 2770 | .block_ptr => |block_scope| { |
| | 2771 | return asRlPtr(mod, scope, rl, src, block_scope.rl_ptr.?, params[1], dest_type); |
| | 2772 | }, |
| | 2773 | |
| 2756 | .bitcasted_ptr => |bitcasted_ptr| { | 2774 | .bitcasted_ptr => |bitcasted_ptr| { |
| 2757 | // TODO here we should be able to resolve the inference; we now have a type for the result. | 2775 | // TODO here we should be able to resolve the inference; we now have a type for the result. |
| 2758 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{}); | 2776 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{}); |
| ... | @@ -2761,13 +2779,47 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I | ... | @@ -2761,13 +2779,47 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I |
| 2761 | // TODO here we should be able to resolve the inference; we now have a type for the result. | 2779 | // TODO here we should be able to resolve the inference; we now have a type for the result. |
| 2762 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{}); | 2780 | return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{}); |
| 2763 | }, | 2781 | }, |
| 2764 | .block_ptr => |block_scope| { | 2782 | } |
| 2765 | const casted_block_ptr = try addZirInstTag(mod, scope, src, .coerce_result_block_ptr, .{ | 2783 | } |
| 2766 | .dest_type = dest_type, | 2784 | |
| 2767 | .block_ptr = block_scope.rl_ptr.?, | 2785 | fn asRlPtr( |
| 2768 | }); | 2786 | mod: *Module, |
| 2769 | return expr(mod, scope, .{ .ptr = casted_block_ptr }, params[1]); | 2787 | scope: *Scope, |
| 2770 | }, | 2788 | rl: ResultLoc, |
| | 2789 | src: usize, |
| | 2790 | result_ptr: *zir.Inst, |
| | 2791 | operand_node: *ast.Node, |
| | 2792 | dest_type: *zir.Inst, |
| | 2793 | ) InnerError!*zir.Inst { |
| | 2794 | // Detect whether this expr() call goes into rvalue() to store the result into the |
| | 2795 | // result location. If it does, elide the coerce_result_ptr instruction |
| | 2796 | // as well as the store instruction, instead passing the result as an rvalue. |
| | 2797 | var as_scope: Scope.GenZIR = .{ |
| | 2798 | .parent = scope, |
| | 2799 | .decl = scope.ownerDecl().?, |
| | 2800 | .arena = scope.arena(), |
| | 2801 | .instructions = .{}, |
| | 2802 | }; |
| | 2803 | defer as_scope.instructions.deinit(mod.gpa); |
| | 2804 | |
| | 2805 | as_scope.rl_ptr = try addZIRBinOp(mod, &as_scope.base, src, .coerce_result_ptr, dest_type, result_ptr); |
| | 2806 | const result = try expr(mod, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node); |
| | 2807 | const parent_zir = &scope.getGenZIR().instructions; |
| | 2808 | if (as_scope.rvalue_rl_count == 1) { |
| | 2809 | // Busted! This expression didn't actually need a pointer. |
| | 2810 | const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2; |
| | 2811 | try parent_zir.ensureCapacity(mod.gpa, expected_len); |
| | 2812 | for (as_scope.instructions.items) |src_inst| { |
| | 2813 | switch (src_inst.tag) { |
| | 2814 | .store_to_block_ptr, .coerce_result_ptr => continue, |
| | 2815 | else => parent_zir.appendAssumeCapacity(src_inst), |
| | 2816 | } |
| | 2817 | } |
| | 2818 | assert(parent_zir.items.len == expected_len); |
| | 2819 | return rvalue(mod, scope, rl, result); |
| | 2820 | } else { |
| | 2821 | try parent_zir.appendSlice(mod.gpa, as_scope.instructions.items); |
| | 2822 | return result; |
| 2771 | } | 2823 | } |
| 2772 | } | 2824 | } |
| 2773 | | 2825 | |