| ... | @@ -601,6 +601,21 @@ stack_size: u32 = 0, | ... | @@ -601,6 +601,21 @@ stack_size: u32 = 0, |
| 601 | /// However, local variables or the usage of `@setAlignStack` can overwrite this default. | 601 | /// However, local variables or the usage of `@setAlignStack` can overwrite this default. |
| 602 | stack_alignment: u32 = 16, | 602 | stack_alignment: u32 = 16, |
| 603 | | 603 | |
| | 604 | // For each individual Wasm valtype we store a seperate free list which |
| | 605 | // allows us to re-use locals that are no longer used. e.g. a temporary local. |
| | 606 | /// A list of indexes which represents a local of valtype `i32`. |
| | 607 | /// It is illegal to store a non-i32 valtype in this list. |
| | 608 | free_locals_i32: std.ArrayListUnmanaged(u32) = .{}, |
| | 609 | /// A list of indexes which represents a local of valtype `i64`. |
| | 610 | /// It is illegal to store a non-i32 valtype in this list. |
| | 611 | free_locals_i64: std.ArrayListUnmanaged(u32) = .{}, |
| | 612 | /// A list of indexes which represents a local of valtype `f32`. |
| | 613 | /// It is illegal to store a non-i32 valtype in this list. |
| | 614 | free_locals_f32: std.ArrayListUnmanaged(u32) = .{}, |
| | 615 | /// A list of indexes which represents a local of valtype `f64`. |
| | 616 | /// It is illegal to store a non-i32 valtype in this list. |
| | 617 | free_locals_f64: std.ArrayListUnmanaged(u32) = .{}, |
| | 618 | |
| 604 | const InnerError = error{ | 619 | const InnerError = error{ |
| 605 | OutOfMemory, | 620 | OutOfMemory, |
| 606 | /// An error occurred when trying to lower AIR to MIR. | 621 | /// An error occurred when trying to lower AIR to MIR. |
| ... | @@ -781,13 +796,43 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void { | ... | @@ -781,13 +796,43 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void { |
| 781 | /// Creates one locals for a given `Type`. | 796 | /// Creates one locals for a given `Type`. |
| 782 | /// Returns a corresponding `Wvalue` with `local` as active tag | 797 | /// Returns a corresponding `Wvalue` with `local` as active tag |
| 783 | fn allocLocal(self: *Self, ty: Type) InnerError!WValue { | 798 | fn allocLocal(self: *Self, ty: Type) InnerError!WValue { |
| | 799 | const valtype = typeToValtype(ty, self.target); |
| | 800 | switch (valtype) { |
| | 801 | .i32 => if (self.free_locals_i32.popOrNull()) |index| { |
| | 802 | return WValue{ .local = index }; |
| | 803 | }, |
| | 804 | .i64 => if (self.free_locals_i64.popOrNull()) |index| { |
| | 805 | return WValue{ .local = index }; |
| | 806 | }, |
| | 807 | .f32 => if (self.free_locals_f32.popOrNull()) |index| { |
| | 808 | return WValue{ .local = index }; |
| | 809 | }, |
| | 810 | .f64 => if (self.free_locals_f64.popOrNull()) |index| { |
| | 811 | return WValue{ .local = index }; |
| | 812 | }, |
| | 813 | } |
| | 814 | // no local was free to be re-used, so allocate a new local instead |
| | 815 | try self.locals.append(self.gpa, wasm.valtype(valtype)); |
| 784 | const initial_index = self.local_index; | 816 | const initial_index = self.local_index; |
| 785 | const valtype = genValtype(ty, self.target); | | |
| 786 | try self.locals.append(self.gpa, valtype); | | |
| 787 | self.local_index += 1; | 817 | self.local_index += 1; |
| 788 | return WValue{ .local = initial_index }; | 818 | return WValue{ .local = initial_index }; |
| 789 | } | 819 | } |
| 790 | | 820 | |
| | 821 | /// Marks a local as no longer being referenced and essentially allows |
| | 822 | /// us to re-use it somewhere else within the function. |
| | 823 | /// The valtype of the local is deducted by using the index of the given. |
| | 824 | /// Asserts given `WValue` is a `local`. |
| | 825 | fn freeLocal(self: *Self, value: WValue) InnerError!WValue { |
| | 826 | const index = value.local; |
| | 827 | const valtype = wasm.valtype(self.locals.items[index]); |
| | 828 | switch (valtype) { |
| | 829 | .i32 => self.free_locals_i32.append(index) catch {}, // It's ok to fail any of those, a new local can be allocated instead |
| | 830 | .i64 => self.free_locals_i64.append(index) catch {}, |
| | 831 | .f32 => self.free_locals_f32.append(index) catch {}, |
| | 832 | .f64 => self.free_locals_f64.append(index) catch {}, |
| | 833 | } |
| | 834 | } |
| | 835 | |
| 791 | /// Generates a `wasm.Type` from a given function type. | 836 | /// Generates a `wasm.Type` from a given function type. |
| 792 | /// Memory is owned by the caller. | 837 | /// Memory is owned by the caller. |
| 793 | fn genFunctype(gpa: Allocator, cc: std.builtin.CallingConvention, params: []const Type, return_type: Type, target: std.Target) !wasm.Type { | 838 | fn genFunctype(gpa: Allocator, cc: std.builtin.CallingConvention, params: []const Type, return_type: Type, target: std.Target) !wasm.Type { |