Skip to content

Commit 6966fb8

Browse files
jacobly0andrewrk
authored andcommitted
wasm2c: reuse locals
* Reduce stack usage of a -O0 build of zig1 by 33%. * Avoid compiler builtin calls.
1 parent 5c67f9c commit 6966fb8

File tree

2 files changed

+488
-739
lines changed

2 files changed

+488
-739
lines changed

stage1/FuncGen.h

+62-12
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@
88
#include <stdbool.h>
99
#include <stdint.h>
1010
#include <stdio.h>
11+
#include <stdlib.h>
1112
#include <string.h>
1213

1314
struct Block {
1415
uint32_t type;
1516
uint32_t label;
1617
uint32_t stack_i;
18+
uint32_t reuse_i;
1719
};
1820

1921
struct FuncGen {
2022
int8_t *type;
23+
uint32_t *reuse;
2124
uint32_t *stack;
2225
struct Block *block;
2326
uint32_t type_i;
27+
uint32_t reuse_i;
2428
uint32_t stack_i;
2529
uint32_t block_i;
2630
uint32_t type_len;
31+
uint32_t reuse_len;
2732
uint32_t stack_len;
2833
uint32_t block_len;
2934
};
@@ -34,13 +39,15 @@ static void FuncGen_init(struct FuncGen *self) {
3439

3540
static void FuncGen_reset(struct FuncGen *self) {
3641
self->type_i = 0;
42+
self->reuse_i = 0;
3743
self->stack_i = 0;
3844
self->block_i = 0;
3945
}
4046

4147
static void FuncGen_free(struct FuncGen *self) {
4248
free(self->block);
4349
free(self->stack);
50+
free(self->reuse);
4451
free(self->type);
4552
}
4653

@@ -65,20 +72,41 @@ static uint32_t FuncGen_localAlloc(struct FuncGen *self, int8_t type) {
6572
self->type = realloc(self->type, sizeof(int8_t) * self->type_len);
6673
if (self->type == NULL) panic("out of memory");
6774
}
68-
uint32_t local_i = self->type_i;
69-
self->type[local_i] = type;
75+
uint32_t local_idx = self->type_i;
76+
self->type[local_idx] = type;
7077
self->type_i += 1;
71-
return local_i;
78+
return local_idx;
79+
}
80+
81+
static enum WasmValType FuncGen_localType(const struct FuncGen *self, uint32_t local_idx) {
82+
return self->type[local_idx];
7283
}
7384

7485
static uint32_t FuncGen_localDeclare(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
75-
uint32_t local_i = FuncGen_localAlloc(self, (int8_t)val_type);
76-
fprintf(out, "%s l%" PRIu32, WasmValType_toC(val_type), local_i);
77-
return local_i;
86+
uint32_t local_idx = FuncGen_localAlloc(self, (int8_t)val_type);
87+
fprintf(out, "%s l%" PRIu32, WasmValType_toC(val_type), local_idx);
88+
return local_idx;
7889
}
7990

80-
static enum WasmValType FuncGen_localType(const struct FuncGen *self, uint32_t local_idx) {
81-
return self->type[local_idx];
91+
static uint32_t FuncGen_reuseTop(const struct FuncGen *self) {
92+
return self->block_i > 0 ? self->block[self->block_i - 1].reuse_i : 0;
93+
}
94+
95+
static void FuncGen_reuseReset(struct FuncGen *self) {
96+
self->reuse_i = FuncGen_reuseTop(self);
97+
}
98+
99+
static uint32_t FuncGen_reuseLocal(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
100+
for (uint32_t i = FuncGen_reuseTop(self); i < self->reuse_i; i += 1) {
101+
uint32_t local_idx = self->reuse[i];
102+
if (FuncGen_localType(self, local_idx) == val_type) {
103+
self->reuse_i -= 1;
104+
self->reuse[i] = self->reuse[self->reuse_i];
105+
fprintf(out, "l%" PRIu32, local_idx);
106+
return local_idx;
107+
}
108+
}
109+
return FuncGen_localDeclare(self, out, val_type);
82110
}
83111

84112
static void FuncGen_stackPush(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
@@ -89,8 +117,7 @@ static void FuncGen_stackPush(struct FuncGen *self, FILE *out, enum WasmValType
89117
if (self->stack == NULL) panic("out of memory");
90118
}
91119
FuncGen_indent(self, out);
92-
fputs("const ", out);
93-
self->stack[self->stack_i] = FuncGen_localDeclare(self, out, val_type);
120+
self->stack[self->stack_i] = FuncGen_reuseLocal(self, out, val_type);
94121
self->stack_i += 1;
95122
fputs(" = ", out);
96123
}
@@ -100,8 +127,17 @@ static uint32_t FuncGen_stackAt(const struct FuncGen *self, uint32_t stack_idx)
100127
}
101128

102129
static uint32_t FuncGen_stackPop(struct FuncGen *self) {
130+
if (self->reuse_i == self->reuse_len) {
131+
self->reuse_len += 10;
132+
self->reuse_len *= 2;
133+
self->reuse = realloc(self->reuse, sizeof(uint32_t) * self->reuse_len);
134+
if (self->reuse == NULL) panic("out of memory");
135+
}
103136
self->stack_i -= 1;
104-
return self->stack[self->stack_i];
137+
uint32_t local_idx = self->stack[self->stack_i];
138+
self->reuse[self->reuse_i] = local_idx;
139+
self->reuse_i += 1;
140+
return local_idx;
105141
}
106142

107143
static void FuncGen_label(struct FuncGen *self, FILE *out, uint32_t label) {
@@ -118,7 +154,6 @@ static void FuncGen_blockBegin(struct FuncGen *self, FILE *out, enum WasmOpcode
118154
self->block = realloc(self->block, sizeof(struct Block) * self->block_len);
119155
if (self->block == NULL) panic("out of memory");
120156
}
121-
uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind);
122157

123158
if (kind == WasmOpcode_if) {
124159
FuncGen_indent(self, out);
@@ -128,11 +163,24 @@ static void FuncGen_blockBegin(struct FuncGen *self, FILE *out, enum WasmOpcode
128163
fputs("{\n", out);
129164
}
130165

166+
uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind);
131167
self->block[self->block_i].type = type < 0 ? ~type : type;
132168
self->block[self->block_i].label = label;
133169
self->block[self->block_i].stack_i = self->stack_i;
170+
self->block[self->block_i].reuse_i = self->reuse_i;
134171
self->block_i += 1;
135172
if (kind == WasmOpcode_loop) FuncGen_label(self, out, label);
173+
174+
uint32_t reuse_top = FuncGen_reuseTop(self);
175+
uint32_t reuse_n = self->reuse_i - reuse_top;
176+
if (reuse_n > self->reuse_len - self->reuse_i) {
177+
self->reuse_len += 10;
178+
self->reuse_len *= 2;
179+
self->reuse = realloc(self->reuse, sizeof(uint32_t) * self->reuse_len);
180+
if (self->reuse == NULL) panic("out of memory");
181+
}
182+
memcpy(&self->reuse[self->reuse_i], &self->reuse[reuse_top], sizeof(uint32_t) * reuse_n);
183+
self->reuse_i += reuse_n;
136184
}
137185

138186
static enum WasmOpcode FuncGen_blockKind(const struct FuncGen *self, uint32_t label_idx) {
@@ -165,6 +213,8 @@ static void FuncGen_blockEnd(struct FuncGen *self, FILE *out) {
165213
fprintf(out, "// stack mismatch %u != %u\n", self->stack_i, self->block[self->block_i].stack_i);
166214
}
167215
self->stack_i = self->block[self->block_i].stack_i;
216+
217+
self->reuse_i = self->block[self->block_i].reuse_i;
168218
}
169219

170220
static bool FuncGen_done(const struct FuncGen *self) {

0 commit comments

Comments
 (0)