authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-21 02:37:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-31 21:09:22-07:00
log2f992e1bb3ff0beb01bd7763a7937000a88f445e
tree2de8db279cda9d5f38d3c54e5b92534b7796e7b9
parent093cbeb018c2df052618bee6602f0f7038327d31

astgen: const locals that end up being rvalues do not alloc

Local variable declarations now detect whether the result location for the initialization expression consumes the result location as a pointer. If it does, then the local is emitted as a LocalPtr. Otherwise it is emitted as a LocalVal. This results in clean, straightforward ZIR code for semantic analysis.

1 files changed, 68 insertions(+), 17 deletions(-)

src/astgen.zig+68-17
...@@ -682,28 +682,77 @@ fn varDecl(...@@ -682,28 +682,77 @@ fn varDecl(
682 return &sub_scope.base;682 return &sub_scope.base;
683 }683 }
684684
685 // Detect whether the initialization expression actually uses the
686 // result location pointer.
687 var init_scope: Scope.GenZIR = .{
688 .parent = scope,
689 .decl = scope.ownerDecl().?,
690 .arena = scope.arena(),
691 .instructions = .{},
692 };
693 defer init_scope.instructions.deinit(mod.gpa);
694
685 var resolve_inferred_alloc: ?*zir.Inst = null;695 var resolve_inferred_alloc: ?*zir.Inst = null;
686 const result_loc = r: {696 if (node.getTypeNode()) |type_node| {
687 if (node.getTypeNode()) |type_node| {697 const type_inst = try typeExpr(mod, &init_scope.base, type_node);
688 const type_inst = try typeExpr(mod, scope, type_node);698 const alloc = try addZIRUnOp(mod, &init_scope.base, name_src, .alloc, type_inst);
689 const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst);699 init_scope.rl_ptr = alloc;
690 break :r ResultLoc{ .ptr = alloc };700 } else {
691 } else {701 const alloc = try addZIRNoOpT(mod, &init_scope.base, name_src, .alloc_inferred);
692 const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred);702 resolve_inferred_alloc = &alloc.base;
693 resolve_inferred_alloc = &alloc.base;703 init_scope.rl_ptr = &alloc.base;
694 break :r ResultLoc{ .inferred_ptr = alloc };704 }
705 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
706 const init_inst = try expr(mod, &init_scope.base, init_result_loc, init_node);
707 const parent_zir = &scope.getGenZIR().instructions;
708 if (init_scope.rvalue_rl_count == 1) {
709 // Result location pointer not used. We don't need an alloc for this
710 // const local, and type inference becomes trivial.
711 // Move the init_scope instructions into the parent scope, eliding
712 // the alloc instruction and the store_to_block_ptr instruction.
713 const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2;
714 try parent_zir.ensureCapacity(mod.gpa, expected_len);
715 for (init_scope.instructions.items) |src_inst| {
716 if (src_inst == init_scope.rl_ptr.?) continue;
717 if (src_inst.castTag(.store_to_block_ptr)) |store| {
718 if (store.positionals.lhs == init_scope.rl_ptr.?) continue;
719 }
720 parent_zir.appendAssumeCapacity(src_inst);
695 }721 }
696 };722 assert(parent_zir.items.len == expected_len);
697 const init_inst = try expr(mod, scope, result_loc, init_node);723 const sub_scope = try block_arena.create(Scope.LocalVal);
724 sub_scope.* = .{
725 .parent = scope,
726 .gen_zir = scope.getGenZIR(),
727 .name = ident_name,
728 .inst = init_inst,
729 };
730 return &sub_scope.base;
731 }
732 // The initialization expression took advantage of the result location
733 // of the const local. In this case we will create an alloc and a LocalPtr for it.
734 // Move the init_scope instructions into the parent scope, swapping
735 // store_to_block_ptr for store_to_inferred_ptr.
736 const expected_len = parent_zir.items.len + init_scope.instructions.items.len;
737 try parent_zir.ensureCapacity(mod.gpa, expected_len);
738 for (init_scope.instructions.items) |src_inst| {
739 if (src_inst.castTag(.store_to_block_ptr)) |store| {
740 if (store.positionals.lhs == init_scope.rl_ptr.?) {
741 src_inst.tag = .store_to_inferred_ptr;
742 }
743 }
744 parent_zir.appendAssumeCapacity(src_inst);
745 }
746 assert(parent_zir.items.len == expected_len);
698 if (resolve_inferred_alloc) |inst| {747 if (resolve_inferred_alloc) |inst| {
699 _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst);748 _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst);
700 }749 }
701 const sub_scope = try block_arena.create(Scope.LocalVal);750 const sub_scope = try block_arena.create(Scope.LocalPtr);
702 sub_scope.* = .{751 sub_scope.* = .{
703 .parent = scope,752 .parent = scope,
704 .gen_zir = scope.getGenZIR(),753 .gen_zir = scope.getGenZIR(),
705 .name = ident_name,754 .name = ident_name,
706 .inst = init_inst,755 .ptr = init_scope.rl_ptr.?,
707 };756 };
708 return &sub_scope.base;757 return &sub_scope.base;
709 },758 },
...@@ -2810,13 +2859,15 @@ fn asRlPtr(...@@ -2810,13 +2859,15 @@ fn asRlPtr(
2810 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;2859 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;
2811 try parent_zir.ensureCapacity(mod.gpa, expected_len);2860 try parent_zir.ensureCapacity(mod.gpa, expected_len);
2812 for (as_scope.instructions.items) |src_inst| {2861 for (as_scope.instructions.items) |src_inst| {
2813 switch (src_inst.tag) {2862 if (src_inst == as_scope.rl_ptr.?) continue;
2814 .store_to_block_ptr, .coerce_result_ptr => continue,2863 if (src_inst.castTag(.store_to_block_ptr)) |store| {
2815 else => parent_zir.appendAssumeCapacity(src_inst),2864 if (store.positionals.lhs == as_scope.rl_ptr.?) continue;
2816 }2865 }
2866 parent_zir.appendAssumeCapacity(src_inst);
2817 }2867 }
2818 assert(parent_zir.items.len == expected_len);2868 assert(parent_zir.items.len == expected_len);
2819 return rvalue(mod, scope, rl, result);2869 const casted_result = try addZIRBinOp(mod, scope, result.src, .as, dest_type, result);
2870 return rvalue(mod, scope, rl, casted_result);
2820 } else {2871 } else {
2821 try parent_zir.appendSlice(mod.gpa, as_scope.instructions.items);2872 try parent_zir.appendSlice(mod.gpa, as_scope.instructions.items);
2822 return result;2873 return result;