╭ FuncGen.h ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 #ifndef FUNC_GEN_H 2 #define FUNC_GEN_H 3 4 #include "panic.h" 5 #include "wasm.h" 6 7 #include <inttypes.h> 8 #include <stdbool.h> 9 #include <stdint.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 struct Block { 15 uint32_t type; 16 uint32_t label; 17 uint32_t stack_i; 18 uint32_t reuse_i; 19 }; 20 21 struct FuncGen { 22 int8_t *type; 23 uint32_t *reuse; 24 uint32_t *stack; 25 struct Block *block; 26 uint32_t type_i; 27 uint32_t reuse_i; 28 uint32_t stack_i; 29 uint32_t block_i; 30 uint32_t type_len; 31 uint32_t reuse_len; 32 uint32_t stack_len; 33 uint32_t block_len; 34 }; 35 36 static void FuncGen_init(struct FuncGen *self) { 37 memset(self, 0, sizeof(struct FuncGen)); 38 } 39 40 static void FuncGen_reset(struct FuncGen *self) { 41 self->type_i = 0; 42 self->reuse_i = 0; 43 self->stack_i = 0; 44 self->block_i = 0; 45 } 46 47 static void FuncGen_free(struct FuncGen *self) { 48 free(self->block); 49 free(self->stack); 50 free(self->reuse); 51 free(self->type); 52 } 53 54 static void FuncGen_outdent(struct FuncGen *self, FILE *out) { 55 for (uint32_t i = 0; i < self->block_i; i += 1) fputs(" ", out); 56 } 57 58 static void FuncGen_indent(struct FuncGen *self, FILE *out) { 59 FuncGen_outdent(self, out); 60 fputs(" ", out); 61 } 62 63 static void FuncGen_cont(struct FuncGen *self, FILE *out) { 64 FuncGen_indent(self, out); 65 fputs(" ", out); 66 } 67 68 static uint32_t FuncGen_localAlloc(struct FuncGen *self, int8_t type) { 69 if (self->type_i == self->type_len) { 70 self->type_len += 10; 71 self->type_len *= 2; 72 self->type = realloc(self->type, sizeof(int8_t) * self->type_len); 73 if (self->type == NULL) panic("out of memory"); 74 } 75 uint32_t local_idx = self->type_i; 76 self->type[local_idx] = type; 77 self->type_i += 1; 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]; 83 } 84 85 static uint32_t FuncGen_localDeclare(struct FuncGen *self, FILE *out, enum WasmValType val_type) { 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; 89 } 90 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); 110 } 111 112 static void FuncGen_stackPush(struct FuncGen *self, FILE *out, enum WasmValType val_type) { 113 if (self->stack_i == self->stack_len) { 114 self->stack_len += 10; 115 self->stack_len *= 2; 116 self->stack = realloc(self->stack, sizeof(uint32_t) * self->stack_len); 117 if (self->stack == NULL) panic("out of memory"); 118 } 119 FuncGen_indent(self, out); 120 self->stack[self->stack_i] = FuncGen_reuseLocal(self, out, val_type); 121 self->stack_i += 1; 122 fputs(" = ", out); 123 } 124 125 static uint32_t FuncGen_stackAt(const struct FuncGen *self, uint32_t stack_idx) { 126 return self->stack[self->stack_i - 1 - stack_idx]; 127 } 128 129 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 } 136 self->stack_i -= 1; 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; 141 } 142 143 static void FuncGen_label(struct FuncGen *self, FILE *out, uint32_t label) { 144 FuncGen_indent(self, out); 145 fprintf(out, "goto l%" PRIu32 ";\n", label); 146 FuncGen_outdent(self, out); 147 fprintf(out, "l%" PRIu32 ":;\n", label); 148 } 149 150 static void FuncGen_blockBegin(struct FuncGen *self, FILE *out, enum WasmOpcode kind, int64_t type) { 151 if (self->block_i == self->block_len) { 152 self->block_len += 10; 153 self->block_len *= 2; 154 self->block = realloc(self->block, sizeof(struct Block) * self->block_len); 155 if (self->block == NULL) panic("out of memory"); 156 } 157 158 if (kind == WasmOpcode_if) { 159 FuncGen_indent(self, out); 160 fprintf(out, "if (l%" PRIu32 ") {\n", FuncGen_stackPop(self)); 161 } else if (EXTRA_BRACES) { 162 FuncGen_indent(self, out); 163 fputs("{\n", out); 164 } 165 166 uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind); 167 self->block[self->block_i].type = type < 0 ? ~type : type; 168 self->block[self->block_i].label = label; 169 self->block[self->block_i].stack_i = self->stack_i; 170 self->block[self->block_i].reuse_i = self->reuse_i; 171 self->block_i += 1; 172 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 if (reuse_n != 0) { 183 memcpy(&self->reuse[self->reuse_i], &self->reuse[reuse_top], sizeof(uint32_t) * reuse_n); 184 self->reuse_i += reuse_n; 185 } 186 } 187 188 static enum WasmOpcode FuncGen_blockKind(const struct FuncGen *self, uint32_t label_idx) { 189 int8_t kind = self->type[self->block[self->block_i - 1 - label_idx].label]; 190 return (enum WasmOpcode)(kind < 0 ? ~kind : kind); 191 } 192 193 static int64_t FuncGen_blockType(const struct FuncGen *self, uint32_t label_idx) { 194 struct Block *block = &self->block[self->block_i - 1 - label_idx]; 195 return self->type[block->label] < 0 ? ~(int64_t)block->type : (int64_t)block->type; 196 } 197 198 static uint32_t FuncGen_blockLabel(const struct FuncGen *self, uint32_t label_idx) { 199 return self->block[self->block_i - 1 - label_idx].label; 200 } 201 202 static void FuncGen_blockEnd(struct FuncGen *self, FILE *out) { 203 enum WasmOpcode kind = FuncGen_blockKind(self, 0); 204 uint32_t label = FuncGen_blockLabel(self, 0); 205 if (kind != WasmOpcode_loop) FuncGen_label(self, out, label); 206 self->block_i -= 1; 207 208 if (EXTRA_BRACES || kind == WasmOpcode_if) { 209 FuncGen_indent(self, out); 210 fputs("}\n", out); 211 } 212 213 if (self->stack_i != self->block[self->block_i].stack_i) { 214 FuncGen_indent(self, out); 215 fprintf(out, "// stack mismatch %u != %u\n", self->stack_i, self->block[self->block_i].stack_i); 216 } 217 self->stack_i = self->block[self->block_i].stack_i; 218 219 self->reuse_i = self->block[self->block_i].reuse_i; 220 } 221 222 static bool FuncGen_done(const struct FuncGen *self) { 223 return self->block_i == 0; 224 } 225 226 #endif /* FUNC_GEN_H */ 227