mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
wasm2c: reuse locals
* Reduce stack usage of a -O0 build of zig1 by 33%. * Avoid compiler builtin calls.
This commit is contained in:
parent
5c67f9ce7a
commit
6966fb8ca5
2 changed files with 465 additions and 716 deletions
|
|
@ -8,22 +8,27 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct Block {
|
||||
uint32_t type;
|
||||
uint32_t label;
|
||||
uint32_t stack_i;
|
||||
uint32_t reuse_i;
|
||||
};
|
||||
|
||||
struct FuncGen {
|
||||
int8_t *type;
|
||||
uint32_t *reuse;
|
||||
uint32_t *stack;
|
||||
struct Block *block;
|
||||
uint32_t type_i;
|
||||
uint32_t reuse_i;
|
||||
uint32_t stack_i;
|
||||
uint32_t block_i;
|
||||
uint32_t type_len;
|
||||
uint32_t reuse_len;
|
||||
uint32_t stack_len;
|
||||
uint32_t block_len;
|
||||
};
|
||||
|
|
@ -34,6 +39,7 @@ static void FuncGen_init(struct FuncGen *self) {
|
|||
|
||||
static void FuncGen_reset(struct FuncGen *self) {
|
||||
self->type_i = 0;
|
||||
self->reuse_i = 0;
|
||||
self->stack_i = 0;
|
||||
self->block_i = 0;
|
||||
}
|
||||
|
|
@ -41,6 +47,7 @@ static void FuncGen_reset(struct FuncGen *self) {
|
|||
static void FuncGen_free(struct FuncGen *self) {
|
||||
free(self->block);
|
||||
free(self->stack);
|
||||
free(self->reuse);
|
||||
free(self->type);
|
||||
}
|
||||
|
||||
|
|
@ -65,22 +72,43 @@ static uint32_t FuncGen_localAlloc(struct FuncGen *self, int8_t type) {
|
|||
self->type = realloc(self->type, sizeof(int8_t) * self->type_len);
|
||||
if (self->type == NULL) panic("out of memory");
|
||||
}
|
||||
uint32_t local_i = self->type_i;
|
||||
self->type[local_i] = type;
|
||||
uint32_t local_idx = self->type_i;
|
||||
self->type[local_idx] = type;
|
||||
self->type_i += 1;
|
||||
return local_i;
|
||||
}
|
||||
|
||||
static uint32_t FuncGen_localDeclare(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
|
||||
uint32_t local_i = FuncGen_localAlloc(self, (int8_t)val_type);
|
||||
fprintf(out, "%s l%" PRIu32, WasmValType_toC(val_type), local_i);
|
||||
return local_i;
|
||||
return local_idx;
|
||||
}
|
||||
|
||||
static enum WasmValType FuncGen_localType(const struct FuncGen *self, uint32_t local_idx) {
|
||||
return self->type[local_idx];
|
||||
}
|
||||
|
||||
static uint32_t FuncGen_localDeclare(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
|
||||
uint32_t local_idx = FuncGen_localAlloc(self, (int8_t)val_type);
|
||||
fprintf(out, "%s l%" PRIu32, WasmValType_toC(val_type), local_idx);
|
||||
return local_idx;
|
||||
}
|
||||
|
||||
static uint32_t FuncGen_reuseTop(const struct FuncGen *self) {
|
||||
return self->block_i > 0 ? self->block[self->block_i - 1].reuse_i : 0;
|
||||
}
|
||||
|
||||
static void FuncGen_reuseReset(struct FuncGen *self) {
|
||||
self->reuse_i = FuncGen_reuseTop(self);
|
||||
}
|
||||
|
||||
static uint32_t FuncGen_reuseLocal(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
|
||||
for (uint32_t i = FuncGen_reuseTop(self); i < self->reuse_i; i += 1) {
|
||||
uint32_t local_idx = self->reuse[i];
|
||||
if (FuncGen_localType(self, local_idx) == val_type) {
|
||||
self->reuse_i -= 1;
|
||||
self->reuse[i] = self->reuse[self->reuse_i];
|
||||
fprintf(out, "l%" PRIu32, local_idx);
|
||||
return local_idx;
|
||||
}
|
||||
}
|
||||
return FuncGen_localDeclare(self, out, val_type);
|
||||
}
|
||||
|
||||
static void FuncGen_stackPush(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
|
||||
if (self->stack_i == self->stack_len) {
|
||||
self->stack_len += 10;
|
||||
|
|
@ -89,8 +117,7 @@ static void FuncGen_stackPush(struct FuncGen *self, FILE *out, enum WasmValType
|
|||
if (self->stack == NULL) panic("out of memory");
|
||||
}
|
||||
FuncGen_indent(self, out);
|
||||
fputs("const ", out);
|
||||
self->stack[self->stack_i] = FuncGen_localDeclare(self, out, val_type);
|
||||
self->stack[self->stack_i] = FuncGen_reuseLocal(self, out, val_type);
|
||||
self->stack_i += 1;
|
||||
fputs(" = ", out);
|
||||
}
|
||||
|
|
@ -100,8 +127,17 @@ static uint32_t FuncGen_stackAt(const struct FuncGen *self, uint32_t stack_idx)
|
|||
}
|
||||
|
||||
static uint32_t FuncGen_stackPop(struct FuncGen *self) {
|
||||
if (self->reuse_i == self->reuse_len) {
|
||||
self->reuse_len += 10;
|
||||
self->reuse_len *= 2;
|
||||
self->reuse = realloc(self->reuse, sizeof(uint32_t) * self->reuse_len);
|
||||
if (self->reuse == NULL) panic("out of memory");
|
||||
}
|
||||
self->stack_i -= 1;
|
||||
return self->stack[self->stack_i];
|
||||
uint32_t local_idx = self->stack[self->stack_i];
|
||||
self->reuse[self->reuse_i] = local_idx;
|
||||
self->reuse_i += 1;
|
||||
return local_idx;
|
||||
}
|
||||
|
||||
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
|
|||
self->block = realloc(self->block, sizeof(struct Block) * self->block_len);
|
||||
if (self->block == NULL) panic("out of memory");
|
||||
}
|
||||
uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind);
|
||||
|
||||
if (kind == WasmOpcode_if) {
|
||||
FuncGen_indent(self, out);
|
||||
|
|
@ -128,11 +163,24 @@ static void FuncGen_blockBegin(struct FuncGen *self, FILE *out, enum WasmOpcode
|
|||
fputs("{\n", out);
|
||||
}
|
||||
|
||||
uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind);
|
||||
self->block[self->block_i].type = type < 0 ? ~type : type;
|
||||
self->block[self->block_i].label = label;
|
||||
self->block[self->block_i].stack_i = self->stack_i;
|
||||
self->block[self->block_i].reuse_i = self->reuse_i;
|
||||
self->block_i += 1;
|
||||
if (kind == WasmOpcode_loop) FuncGen_label(self, out, label);
|
||||
|
||||
uint32_t reuse_top = FuncGen_reuseTop(self);
|
||||
uint32_t reuse_n = self->reuse_i - reuse_top;
|
||||
if (reuse_n > self->reuse_len - self->reuse_i) {
|
||||
self->reuse_len += 10;
|
||||
self->reuse_len *= 2;
|
||||
self->reuse = realloc(self->reuse, sizeof(uint32_t) * self->reuse_len);
|
||||
if (self->reuse == NULL) panic("out of memory");
|
||||
}
|
||||
memcpy(&self->reuse[self->reuse_i], &self->reuse[reuse_top], sizeof(uint32_t) * reuse_n);
|
||||
self->reuse_i += reuse_n;
|
||||
}
|
||||
|
||||
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) {
|
|||
fprintf(out, "// stack mismatch %u != %u\n", self->stack_i, self->block[self->block_i].stack_i);
|
||||
}
|
||||
self->stack_i = self->block[self->block_i].stack_i;
|
||||
|
||||
self->reuse_i = self->block[self->block_i].reuse_i;
|
||||
}
|
||||
|
||||
static bool FuncGen_done(const struct FuncGen *self) {
|
||||
|
|
|
|||
1105
stage1/wasm2c.c
1105
stage1/wasm2c.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue