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...@@ -789,8 +789,13 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
789fn processDeath(self: *Self, ref: Air.Inst.Ref) void {789fn processDeath(self: *Self, ref: Air.Inst.Ref) void {
790 const inst = Air.refToIndex(ref) orelse return;790 const inst = Air.refToIndex(ref) orelse return;
791 if (self.air.instructions.items(.tag)[inst] == .constant) return;791 if (self.air.instructions.items(.tag)[inst] == .constant) return;
792 var value = self.values.get(ref) orelse return;792 const value = self.values.getPtr(ref) orelse return;
793 value.free(self);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 }
794}799}
795800
796/// Appends a MIR instruction and returns its index within the list of instructions801/// 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 {...@@ -909,10 +914,29 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void {
909 try self.addInst(.{ .tag = .memory_address, .data = .{ .payload = extra_index } });914 try self.addInst(.{ .tag = .memory_address, .data = .{ .payload = extra_index } });
910 },915 },
911 .function_index => |index| try self.addLabel(.function_index, index), // write function index and generate relocation916 .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 offset917 .stack_offset => try self.addLabel(.local_get, self.bottom_stack_value.local.value), // caller must ensure to address the offset
913 }918 }
914}919}
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
916/// Creates one locals for a given `Type`.940/// Creates one locals for a given `Type`.
917/// Returns a corresponding `Wvalue` with `local` as active tag941/// Returns a corresponding `Wvalue` with `local` as active tag
918fn allocLocal(self: *Self, ty: Type) InnerError!WValue {942fn allocLocal(self: *Self, ty: Type) InnerError!WValue {
...@@ -2956,7 +2980,8 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -2956,7 +2980,8 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!void {
2956fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!void {2980fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!void {
2957 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2981 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2958 const result = if (!self.liveness.isUnused(inst)) result: {2982 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);
2960 } else WValue{ .none = {} };2985 } else WValue{ .none = {} };
2961 self.finishAir(inst, result, &.{});2986 self.finishAir(inst, result, &.{});
2962}2987}