authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-21 01:30:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-31 21:09:22-07:00
log093cbeb018c2df052618bee6602f0f7038327d31
treecd532f9a1ccde0d30f8806c3b7fcbef2e6fd833a
parentb7452fe35f514d4c04aae4582bc8071bc9e70f1b

astgen: `@as` with block_ptr result location


3 files changed, 86 insertions(+), 62 deletions(-)

src/astgen.zig+85-33
...@@ -663,11 +663,27 @@ fn varDecl(...@@ -663,11 +663,27 @@ fn varDecl(
663663
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 lvalue666 // 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 as667 // 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}
27302749
2731fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {2750fn 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.?,2785fn 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}
27732825
src/zir.zig+1-18
...@@ -112,10 +112,6 @@ pub const Inst = struct {...@@ -112,10 +112,6 @@ pub const Inst = struct {
112 /// as type coercion from the new element type to the old element type.112 /// as type coercion from the new element type to the old element type.
113 /// LHS is destination element type, RHS is result pointer.113 /// LHS is destination element type, RHS is result pointer.
114 coerce_result_ptr,114 coerce_result_ptr,
115 /// This instruction does a `coerce_result_ptr` operation on a `Block`'s
116 /// result location pointer, whose type is inferred by peer type resolution on the
117 /// `Block`'s corresponding `break` instructions.
118 coerce_result_block_ptr,
119 /// Emit an error message and fail compilation.115 /// Emit an error message and fail compilation.
120 compile_error,116 compile_error,
121 /// Log compile time variables and emit an error message.117 /// Log compile time variables and emit an error message.
...@@ -460,7 +456,6 @@ pub const Inst = struct {...@@ -460,7 +456,6 @@ pub const Inst = struct {
460 .decl_ref => DeclRef,456 .decl_ref => DeclRef,
461 .decl_ref_str => DeclRefStr,457 .decl_ref_str => DeclRefStr,
462 .decl_val => DeclVal,458 .decl_val => DeclVal,
463 .coerce_result_block_ptr => CoerceResultBlockPtr,
464 .compile_log => CompileLog,459 .compile_log => CompileLog,
465 .loop => Loop,460 .loop => Loop,
466 .@"const" => Const,461 .@"const" => Const,
...@@ -531,7 +526,6 @@ pub const Inst = struct {...@@ -531,7 +526,6 @@ pub const Inst = struct {
531 .cmp_gt,526 .cmp_gt,
532 .cmp_neq,527 .cmp_neq,
533 .coerce_result_ptr,528 .coerce_result_ptr,
534 .coerce_result_block_ptr,
535 .@"const",529 .@"const",
536 .dbg_stmt,530 .dbg_stmt,
537 .decl_ref,531 .decl_ref,
...@@ -771,17 +765,6 @@ pub const Inst = struct {...@@ -771,17 +765,6 @@ pub const Inst = struct {
771 kw_args: struct {},765 kw_args: struct {},
772 };766 };
773767
774 pub const CoerceResultBlockPtr = struct {
775 pub const base_tag = Tag.coerce_result_block_ptr;
776 base: Inst,
777
778 positionals: struct {
779 dest_type: *Inst,
780 block_ptr: *Inst,
781 },
782 kw_args: struct {},
783 };
784
785 pub const CompileLog = struct {768 pub const CompileLog = struct {
786 pub const base_tag = Tag.compile_log;769 pub const base_tag = Tag.compile_log;
787 base: Inst,770 base: Inst,
...@@ -1464,7 +1447,7 @@ const Writer = struct {...@@ -1464,7 +1447,7 @@ const Writer = struct {
1464 TypedValue => return stream.print("TypedValue{{ .ty = {}, .val = {}}}", .{ param.ty, param.val }),1447 TypedValue => return stream.print("TypedValue{{ .ty = {}, .val = {}}}", .{ param.ty, param.val }),
1465 *IrModule.Decl => return stream.print("Decl({s})", .{param.name}),1448 *IrModule.Decl => return stream.print("Decl({s})", .{param.name}),
1466 *Inst.Block => {1449 *Inst.Block => {
1467 const name = self.block_table.get(param).?;1450 const name = self.block_table.get(param) orelse "!BADREF!";
1468 return stream.print("\"{}\"", .{std.zig.fmtEscapes(name)});1451 return stream.print("\"{}\"", .{std.zig.fmtEscapes(name)});
1469 },1452 },
1470 *Inst.Loop => {1453 *Inst.Loop => {
src/zir_sema.zig-11
...@@ -43,7 +43,6 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -43,7 +43,6 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
43 .breakpoint => return zirBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?),43 .breakpoint => return zirBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?),
44 .break_void => return zirBreakVoid(mod, scope, old_inst.castTag(.break_void).?),44 .break_void => return zirBreakVoid(mod, scope, old_inst.castTag(.break_void).?),
45 .call => return zirCall(mod, scope, old_inst.castTag(.call).?),45 .call => return zirCall(mod, scope, old_inst.castTag(.call).?),
46 .coerce_result_block_ptr => return zirCoerceResultBlockPtr(mod, scope, old_inst.castTag(.coerce_result_block_ptr).?),
47 .coerce_result_ptr => return zirCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?),46 .coerce_result_ptr => return zirCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?),
48 .compile_error => return zirCompileError(mod, scope, old_inst.castTag(.compile_error).?),47 .compile_error => return zirCompileError(mod, scope, old_inst.castTag(.compile_error).?),
49 .compile_log => return zirCompileLog(mod, scope, old_inst.castTag(.compile_log).?),48 .compile_log => return zirCompileLog(mod, scope, old_inst.castTag(.compile_log).?),
...@@ -265,16 +264,6 @@ fn analyzeConstInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError...@@ -265,16 +264,6 @@ fn analyzeConstInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError
265 };264 };
266}265}
267266
268fn zirCoerceResultBlockPtr(
269 mod: *Module,
270 scope: *Scope,
271 inst: *zir.Inst.CoerceResultBlockPtr,
272) InnerError!*Inst {
273 const tracy = trace(@src());
274 defer tracy.end();
275 return mod.fail(scope, inst.base.src, "TODO implement zirCoerceResultBlockPtr", .{});
276}
277
278fn zirBitcastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {267fn zirBitcastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
279 const tracy = trace(@src());268 const tracy = trace(@src());
280 defer tracy.end();269 defer tracy.end();