@@ -601,6 +601,21 @@ stack_size: u32 = 0,
601
601
/// However, local variables or the usage of `@setAlignStack` can overwrite this default.
602
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
619
const InnerError = error {
605
620
OutOfMemory ,
606
621
/// An error occurred when trying to lower AIR to MIR.
@@ -781,13 +796,43 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void {
781
796
/// Creates one locals for a given `Type`.
782
797
/// Returns a corresponding `Wvalue` with `local` as active tag
783
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
816
const initial_index = self .local_index ;
785
- const valtype = genValtype (ty , self .target );
786
- try self .locals .append (self .gpa , valtype );
787
817
self .local_index += 1 ;
788
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
836
/// Generates a `wasm.Type` from a given function type.
792
837
/// Memory is owned by the caller.
793
838
fn genFunctype (gpa : Allocator , cc : std.builtin.CallingConvention , params : []const Type , return_type : Type , target : std.Target ) ! wasm.Type {
0 commit comments