authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-10-13 21:33:26+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-10-16 15:54:16+02:00
log576bb3f0a965cd7ff3dad6076567657f18d6675e
treee6db50bc8e680c73935f3f392b754ed4c8a4e164
parentb17c8c542420e14e24ec397b248dfc101a08421e
signaturelock-open Commit is signed but in an unrecognized format.

wasm: de -and increment reference count locals

When reusing an operand it increases the reference count, then when an operand dies it will only decrease the reference count. When this reaches 0, the local will be virtually freed, meaning it can be re-used for a new local.

1 files changed, 29 insertions(+), 4 deletions(-)

src/arch/wasm/CodeGen.zig+29-4
......@@ -789,8 +789,13 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
789789fn processDeath(self: *Self, ref: Air.Inst.Ref) void {
790790 const inst = Air.refToIndex(ref) orelse return;
791791 if (self.air.instructions.items(.tag)[inst] == .constant) return;
792 var value = self.values.get(ref) orelse return;
793 value.free(self);
792 const value = self.values.getPtr(ref) orelse return;
793 if (value.* != .local) return;
794 std.debug.print("Decreasing reference for ref: %{?d}\n", .{Air.refToIndex(ref)});
795 value.local.references -= 1; // if this panics, a call to `reuseOperand` was forgotten by the developer
796 if (value.local.references == 0) {
797 value.free(self);
798 }
794799}
795800
796801/// Appends a MIR instruction and returns its index within the list of instructions
......@@ -909,10 +914,29 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void {
909914 try self.addInst(.{ .tag = .memory_address, .data = .{ .payload = extra_index } });
910915 },
911916 .function_index => |index| try self.addLabel(.function_index, index), // write function index and generate relocation
912 .stack_offset => try self.addLabel(.local_get, self.bottom_stack_value.local), // caller must ensure to address the offset
917 .stack_offset => try self.addLabel(.local_get, self.bottom_stack_value.local.value), // caller must ensure to address the offset
913918 }
914919}
915920
921/// If given a local or stack-offset, increases the reference count by 1.
922/// The old `WValue` found at instruction `ref` is then replaced by the
923/// modified `WValue` and returned. When given a non-local or non-stack-offset,
924/// returns the given `operand` itself instead.
925fn reuseOperand(self: *Self, ref: Air.Inst.Ref, operand: WValue) WValue {
926 if (operand != .local and operand != .stack_offset) return operand;
927 var copy = operand;
928 switch (copy) {
929 .local => |*local| local.references += 1,
930 .stack_offset => |*stack_offset| stack_offset.references += 1,
931 else => unreachable,
932 }
933
934 const gop = self.values.getOrPutAssumeCapacity(ref);
935 assert(gop.found_existing);
936 gop.value_ptr.* = copy;
937 return copy;
938}
939
916940/// Creates one locals for a given `Type`.
917941/// Returns a corresponding `Wvalue` with `local` as active tag
918942fn allocLocal(self: *Self, ty: Type) InnerError!WValue {
......@@ -2956,7 +2980,8 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!void {
29562980fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!void {
29572981 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
29582982 const result = if (!self.liveness.isUnused(inst)) result: {
2959 break :result try self.resolveInst(ty_op.operand);
2983 const operand = try self.resolveInst(ty_op.operand);
2984 break :result self.reuseOperand(ty_op.operand, operand);
29602985 } else WValue{ .none = {} };
29612986 self.finishAir(inst, result, &.{});
29622987}