authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-12-08 21:29:42-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-09 03:45:29-05:00
log6966fb8ca5608cae122434a50ff2cd264502c0eb
treedb686902c404fbfabd181a03eb6c814afc1fcf0a
parent5c67f9ce7a4d9f5aedbe8cfba1f361922701a144

wasm2c: reuse locals

* Reduce stack usage of a -O0 build of zig1 by 33%. * Avoid compiler builtin calls.

2 files changed, 488 insertions(+), 739 deletions(-)

stage1/FuncGen.h+62-12
......@@ -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
1314struct Block {
1415 uint32_t type;
1516 uint32_t label;
1617 uint32_t stack_i;
18 uint32_t reuse_i;
1719};
1820
1921struct 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,6 +39,7 @@ static void FuncGen_init(struct FuncGen *self) {
3439
3540static 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}
......@@ -41,6 +47,7 @@ static void FuncGen_reset(struct FuncGen *self) {
4147static 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
81static enum WasmValType FuncGen_localType(const struct FuncGen *self, uint32_t local_idx) {
82 return self->type[local_idx];
7283}
7384
7485static 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
80static enum WasmValType FuncGen_localType(const struct FuncGen *self, uint32_t local_idx) {
81 return self->type[local_idx];
91static 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
95static void FuncGen_reuseReset(struct FuncGen *self) {
96 self->reuse_i = FuncGen_reuseTop(self);
97}
98
99static 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
84112static 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
102129static 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
107143static 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
138186static 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
170220static bool FuncGen_done(const struct FuncGen *self) {
stage1/wasm2c.c+426-727
......@@ -97,21 +97,20 @@ int main(int argc, char **argv) {
9797 "#include <stdint.h>\n"
9898 "#include <stdlib.h>\n"
9999 "#include <string.h>\n"
100 "\n"
101 "static uint16_t i16_byteswap(uint16_t src) {\n"
102 " return (uint16_t)(uint8_t)(src >> 0) << 8 |\n"
103 " (uint16_t)(uint8_t)(src >> 8) << 0;\n"
104 "}\n"
105 "static uint32_t i32_byteswap(uint32_t src) {\n"
106 " return (uint32_t)i16_byteswap(src >> 0) << 16 |\n"
107 " (uint32_t)i16_byteswap(src >> 16) << 0;\n"
108 "}\n"
109 "static uint64_t i64_byteswap(uint64_t src) {\n"
110 " return (uint64_t)i32_byteswap(src >> 0) << 32 |\n"
111 " (uint64_t)i32_byteswap(src >> 32) << 0;\n"
112 "}\n"
100113 "\n", out);
101 if (is_big_endian)
102 fputs("static uint16_t i16_byteswap(uint16_t src) {\n"
103 " return (uint16_t)(uint8_t)(src >> 0) << 8 |\n"
104 " (uint16_t)(uint8_t)(src >> 8) << 0;\n"
105 "}\n"
106 "static uint32_t i32_byteswap(uint32_t src) {\n"
107 " return (uint32_t)i16_byteswap(src >> 0) << 16 |\n"
108 " (uint32_t)i16_byteswap(src >> 16) << 0;\n"
109 "}\n"
110 "static uint64_t i64_byteswap(uint64_t src) {\n"
111 " return (uint64_t)i32_byteswap(src >> 0) << 32 |\n"
112 " (uint64_t)i32_byteswap(src >> 32) << 0;\n"
113 "}\n"
114 "\n", out);
115114 fputs("static uint16_t load16_align0(const uint8_t *ptr) {\n"
116115 " uint16_t val;\n"
117116 " memcpy(&val, ptr, sizeof(val));\n", out);
......@@ -165,6 +164,39 @@ int main(int argc, char **argv) {
165164 " memcpy(&val, ptr, sizeof(val));\n", out);
166165 if (is_big_endian) fputs(" val = i64_byteswap(val);", out);
167166 fputs(" return val;\n"
167 "}\n"
168 "\n"
169 "static uint32_t i32_popcnt(uint32_t lhs) {\n"
170 " lhs = lhs - ((lhs >> 1) & UINT32_C(0x55555555));\n"
171 " lhs = (lhs & UINT32_C(0x33333333)) + ((lhs >> 2) & UINT32_C(0x33333333));\n"
172 " lhs = (lhs + (lhs >> 4)) & UINT32_C(0x0F0F0F0F);\n"
173 " return (lhs * UINT32_C(0x01010101)) >> 24;\n"
174 "}\n"
175 "static uint32_t i32_ctz(uint32_t lhs) {\n"
176 " return i32_popcnt(~lhs & (lhs - 1));\n"
177 "}\n"
178 "static uint32_t i32_clz(uint32_t lhs) {\n"
179 " lhs = i32_byteswap(lhs);\n"
180 " lhs = (lhs & UINT32_C(0x0F0F0F0F)) << 4 | (lhs & UINT32_C(0xF0F0F0F0)) >> 4;\n"
181 " lhs = (lhs & UINT32_C(0x33333333)) << 2 | (lhs & UINT32_C(0xCCCCCCCC)) >> 2;\n"
182 " lhs = (lhs & UINT32_C(0x55555555)) << 1 | (lhs & UINT32_C(0xAAAAAAAA)) >> 1;\n"
183 " return i32_ctz(lhs);\n"
184 "}\n"
185 "static uint64_t i64_popcnt(uint64_t lhs) {\n"
186 " lhs = lhs - ((lhs >> 1) & UINT64_C(0x5555555555555555));\n"
187 " lhs = (lhs & UINT64_C(0x3333333333333333)) + ((lhs >> 2) & UINT64_C(0x3333333333333333));\n"
188 " lhs = (lhs + (lhs >> 4)) & UINT64_C(0x0F0F0F0F0F0F0F0F);\n"
189 " return (lhs * UINT64_C(0x0101010101010101)) >> 56;\n"
190 "}\n"
191 "static uint64_t i64_ctz(uint64_t lhs) {\n"
192 " return i64_popcnt(~lhs & (lhs - 1));\n"
193 "}\n"
194 "static uint64_t i64_clz(uint64_t lhs) {\n"
195 " lhs = i64_byteswap(lhs);\n"
196 " lhs = (lhs & UINT64_C(0x0F0F0F0F0F0F0F0F)) << 4 | (lhs & UINT32_C(0xF0F0F0F0F0F0F0F0)) >> 4;\n"
197 " lhs = (lhs & UINT64_C(0x3333333333333333)) << 2 | (lhs & UINT32_C(0xCCCCCCCCCCCCCCCC)) >> 2;\n"
198 " lhs = (lhs & UINT64_C(0x5555555555555555)) << 1 | (lhs & UINT32_C(0xAAAAAAAAAAAAAAAA)) >> 1;\n"
199 " return i64_ctz(lhs);\n"
168200 "}\n"
169201 "\n"
170202 "static void store16_align0(uint8_t *ptr, uint16_t val) {\n", out);
......@@ -787,6 +819,7 @@ int main(int argc, char **argv) {
787819 } else unreachable_depth -= 1;
788820 switch (opcode) {
789821 case WasmOpcode_else:
822 FuncGen_reuseReset(&fg);
790823 FuncGen_outdent(&fg, out);
791824 fputs("} else {\n", out);
792825 break;
......@@ -968,10 +1001,10 @@ int main(int argc, char **argv) {
9681001 if (unreachable_depth == 0) {
9691002 uint32_t cond = FuncGen_stackPop(&fg);
9701003 uint32_t rhs = FuncGen_stackPop(&fg);
971 uint32_t lhs = FuncGen_stackPop(&fg);
972 FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, lhs));
973 fprintf(out, "l%" PRIu32 " ? l%" PRIu32 " : l%" PRIu32 ";\n",
974 cond, lhs, rhs);
1004 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1005 FuncGen_indent(&fg, out);
1006 fprintf(out, "l%"PRIu32" = l%" PRIu32 " ? l%" PRIu32 " : l%" PRIu32 ";\n",
1007 lhs, cond, lhs, rhs);
9751008 }
9761009 break;
9771010
......@@ -1369,89 +1402,55 @@ int main(int argc, char **argv) {
13691402
13701403 case WasmOpcode_i32_eqz:
13711404 if (unreachable_depth == 0) {
1372 uint32_t lhs = FuncGen_stackPop(&fg);
1373 FuncGen_stackPush(&fg, out, WasmValType_i32);
1374 fprintf(out, "!l%" PRIu32 ";\n", lhs);
1405 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1406 FuncGen_indent(&fg, out);
1407 fprintf(out, "l%" PRIu32 " = !l%" PRIu32 ";\n", lhs, lhs);
13751408 }
13761409 break;
13771410 case WasmOpcode_i32_eq:
1378 if (unreachable_depth == 0) {
1379 uint32_t rhs = FuncGen_stackPop(&fg);
1380 uint32_t lhs = FuncGen_stackPop(&fg);
1381 FuncGen_stackPush(&fg, out, WasmValType_i32);
1382 fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
1383 }
1384 break;
13851411 case WasmOpcode_i32_ne:
1386 if (unreachable_depth == 0) {
1387 uint32_t rhs = FuncGen_stackPop(&fg);
1388 uint32_t lhs = FuncGen_stackPop(&fg);
1389 FuncGen_stackPush(&fg, out, WasmValType_i32);
1390 fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
1391 }
1392 break;
1393 case WasmOpcode_i32_lt_s:
1394 if (unreachable_depth == 0) {
1395 uint32_t rhs = FuncGen_stackPop(&fg);
1396 uint32_t lhs = FuncGen_stackPop(&fg);
1397 FuncGen_stackPush(&fg, out, WasmValType_i32);
1398 fprintf(out, "(int32_t)l%" PRIu32 " < (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1399 }
1400 break;
14011412 case WasmOpcode_i32_lt_u:
1402 if (unreachable_depth == 0) {
1403 uint32_t rhs = FuncGen_stackPop(&fg);
1404 uint32_t lhs = FuncGen_stackPop(&fg);
1405 FuncGen_stackPush(&fg, out, WasmValType_i32);
1406 fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
1407 }
1408 break;
1409 case WasmOpcode_i32_gt_s:
1410 if (unreachable_depth == 0) {
1411 uint32_t rhs = FuncGen_stackPop(&fg);
1412 uint32_t lhs = FuncGen_stackPop(&fg);
1413 FuncGen_stackPush(&fg, out, WasmValType_i32);
1414 fprintf(out, "(int32_t)l%" PRIu32 " > (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1415 }
1416 break;
14171413 case WasmOpcode_i32_gt_u:
1418 if (unreachable_depth == 0) {
1419 uint32_t rhs = FuncGen_stackPop(&fg);
1420 uint32_t lhs = FuncGen_stackPop(&fg);
1421 FuncGen_stackPush(&fg, out, WasmValType_i32);
1422 fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
1423 }
1424 break;
1425 case WasmOpcode_i32_le_s:
1426 if (unreachable_depth == 0) {
1427 uint32_t rhs = FuncGen_stackPop(&fg);
1428 uint32_t lhs = FuncGen_stackPop(&fg);
1429 FuncGen_stackPush(&fg, out, WasmValType_i32);
1430 fprintf(out, "(int32_t)l%" PRIu32 " <= (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1431 }
1432 break;
14331414 case WasmOpcode_i32_le_u:
1415 case WasmOpcode_i32_ge_u:
1416 // i32 unsigned comparisons
14341417 if (unreachable_depth == 0) {
14351418 uint32_t rhs = FuncGen_stackPop(&fg);
1436 uint32_t lhs = FuncGen_stackPop(&fg);
1437 FuncGen_stackPush(&fg, out, WasmValType_i32);
1438 fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
1419 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1420 const char *operator;
1421 switch (opcode) {
1422 case WasmOpcode_i32_eq: operator = "=="; break;
1423 case WasmOpcode_i32_ne: operator = "!="; break;
1424 case WasmOpcode_i32_lt_u: operator = "<"; break;
1425 case WasmOpcode_i32_gt_u: operator = ">"; break;
1426 case WasmOpcode_i32_le_u: operator = "<="; break;
1427 case WasmOpcode_i32_ge_u: operator = ">="; break;
1428 default: panic("unreachable");
1429 }
1430 FuncGen_indent(&fg, out);
1431 fprintf(out, "l%" PRIu32 " = l%" PRIu32 " %s l%" PRIu32 ";\n",
1432 lhs, lhs, operator, rhs);
14391433 }
14401434 break;
1435 case WasmOpcode_i32_lt_s:
1436 case WasmOpcode_i32_gt_s:
1437 case WasmOpcode_i32_le_s:
14411438 case WasmOpcode_i32_ge_s:
1439 // i32 signed comparisons
14421440 if (unreachable_depth == 0) {
14431441 uint32_t rhs = FuncGen_stackPop(&fg);
1444 uint32_t lhs = FuncGen_stackPop(&fg);
1445 FuncGen_stackPush(&fg, out, WasmValType_i32);
1446 fprintf(out, "(int32_t)l%" PRIu32 " >= (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1447 }
1448 break;
1449 case WasmOpcode_i32_ge_u:
1450 if (unreachable_depth == 0) {
1451 uint32_t rhs = FuncGen_stackPop(&fg);
1452 uint32_t lhs = FuncGen_stackPop(&fg);
1453 FuncGen_stackPush(&fg, out, WasmValType_i32);
1454 fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
1442 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1443 const char *operator;
1444 switch (opcode) {
1445 case WasmOpcode_i32_lt_s: operator = "<"; break;
1446 case WasmOpcode_i32_gt_s: operator = ">"; break;
1447 case WasmOpcode_i32_le_s: operator = "<="; break;
1448 case WasmOpcode_i32_ge_s: operator = ">="; break;
1449 default: panic("unreachable");
1450 }
1451 FuncGen_indent(&fg, out);
1452 fprintf(out, "l%" PRIu32 " = (int32_t)l%" PRIu32 " %s (int32_t)l%" PRIu32
1453 ";\n", lhs, lhs, operator, rhs);
14551454 }
14561455 break;
14571456
......@@ -1463,685 +1462,385 @@ int main(int argc, char **argv) {
14631462 }
14641463 break;
14651464 case WasmOpcode_i64_eq:
1466 if (unreachable_depth == 0) {
1467 uint32_t rhs = FuncGen_stackPop(&fg);
1468 uint32_t lhs = FuncGen_stackPop(&fg);
1469 FuncGen_stackPush(&fg, out, WasmValType_i32);
1470 fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
1471 }
1472 break;
14731465 case WasmOpcode_i64_ne:
1466 case WasmOpcode_i64_lt_u:
1467 case WasmOpcode_i64_gt_u:
1468 case WasmOpcode_i64_le_u:
1469 case WasmOpcode_i64_ge_u:
1470 case WasmOpcode_f32_eq:
1471 case WasmOpcode_f32_ne:
1472 case WasmOpcode_f32_lt:
1473 case WasmOpcode_f32_gt:
1474 case WasmOpcode_f32_le:
1475 case WasmOpcode_f32_ge:
1476 case WasmOpcode_f64_eq:
1477 case WasmOpcode_f64_ne:
1478 case WasmOpcode_f64_lt:
1479 case WasmOpcode_f64_gt:
1480 case WasmOpcode_f64_le:
1481 case WasmOpcode_f64_ge:
1482 // non-i32 unsigned comparisons
14741483 if (unreachable_depth == 0) {
14751484 uint32_t rhs = FuncGen_stackPop(&fg);
14761485 uint32_t lhs = FuncGen_stackPop(&fg);
1486 const char *operator;
1487 switch (opcode) {
1488 case WasmOpcode_i64_eq:
1489 case WasmOpcode_f32_eq:
1490 case WasmOpcode_f64_eq:
1491 operator = "==";
1492 break;
1493 case WasmOpcode_i64_ne:
1494 case WasmOpcode_f32_ne:
1495 case WasmOpcode_f64_ne:
1496 operator = "!=";
1497 break;
1498 case WasmOpcode_i64_lt_u:
1499 case WasmOpcode_f32_lt:
1500 case WasmOpcode_f64_lt:
1501 operator = "<";
1502 break;
1503 case WasmOpcode_i64_gt_u:
1504 case WasmOpcode_f32_gt:
1505 case WasmOpcode_f64_gt:
1506 operator = ">";
1507 break;
1508 case WasmOpcode_i64_le_u:
1509 case WasmOpcode_f32_le:
1510 case WasmOpcode_f64_le:
1511 operator = "<=";
1512 break;
1513 case WasmOpcode_i64_ge_u:
1514 case WasmOpcode_f32_ge:
1515 case WasmOpcode_f64_ge:
1516 operator = ">=";
1517 break;
1518 default: panic("unreachable");
1519 }
14771520 FuncGen_stackPush(&fg, out, WasmValType_i32);
1478 fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
1521 fprintf(out, "l%" PRIu32 " = l%" PRIu32 " %s l%" PRIu32 ";\n",
1522 lhs, lhs, operator, rhs);
14791523 }
14801524 break;
14811525 case WasmOpcode_i64_lt_s:
1526 case WasmOpcode_i64_gt_s:
1527 case WasmOpcode_i64_le_s:
1528 case WasmOpcode_i64_ge_s:
1529 // i64 signed comparisons
14821530 if (unreachable_depth == 0) {
14831531 uint32_t rhs = FuncGen_stackPop(&fg);
14841532 uint32_t lhs = FuncGen_stackPop(&fg);
1533 const char *operator;
1534 switch (opcode) {
1535 case WasmOpcode_i64_lt_s: operator = "<"; break;
1536 case WasmOpcode_i64_gt_s: operator = ">"; break;
1537 case WasmOpcode_i64_le_s: operator = "<="; break;
1538 case WasmOpcode_i64_ge_s: operator = ">="; break;
1539 default: panic("unreachable");
1540 }
14851541 FuncGen_stackPush(&fg, out, WasmValType_i32);
1486 fprintf(out, "(int64_t)l%" PRIu32 " < (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1542 fprintf(out, "l%" PRIu32 " = (int64_t)l%" PRIu32 " %s (int64_t)l%" PRIu32
1543 ";\n", lhs, lhs, operator, rhs);
14871544 }
14881545 break;
1489 case WasmOpcode_i64_lt_u:
1546
1547 case WasmOpcode_i32_clz:
1548 case WasmOpcode_i32_ctz:
1549 case WasmOpcode_i32_popcnt:
1550 case WasmOpcode_i64_clz:
1551 case WasmOpcode_i64_ctz:
1552 case WasmOpcode_i64_popcnt:
1553 case WasmOpcode_f32_abs:
1554 case WasmOpcode_f32_neg:
1555 case WasmOpcode_f32_ceil:
1556 case WasmOpcode_f32_floor:
1557 case WasmOpcode_f32_trunc:
1558 case WasmOpcode_f32_nearest:
1559 case WasmOpcode_f32_sqrt:
1560 case WasmOpcode_f64_abs:
1561 case WasmOpcode_f64_neg:
1562 case WasmOpcode_f64_ceil:
1563 case WasmOpcode_f64_floor:
1564 case WasmOpcode_f64_trunc:
1565 case WasmOpcode_f64_nearest:
1566 case WasmOpcode_f64_sqrt:
1567 // unary functions
14901568 if (unreachable_depth == 0) {
1491 uint32_t rhs = FuncGen_stackPop(&fg);
1492 uint32_t lhs = FuncGen_stackPop(&fg);
1493 FuncGen_stackPush(&fg, out, WasmValType_i32);
1494 fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
1569 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1570 const char *function;
1571 switch (opcode) {
1572 case WasmOpcode_i32_clz: function = "i32_clz"; break;
1573 case WasmOpcode_i32_ctz: function = "i32_ctz"; break;
1574 case WasmOpcode_i32_popcnt: function = "i32_popcnt"; break;
1575 case WasmOpcode_i64_clz: function = "i64_clz"; break;
1576 case WasmOpcode_i64_ctz: function = "i64_ctz"; break;
1577 case WasmOpcode_i64_popcnt: function = "i64_popcnt"; break;
1578 case WasmOpcode_f32_abs: function = "fabsf"; break;
1579 case WasmOpcode_f32_neg:
1580 case WasmOpcode_f64_neg: function = "-"; break;
1581 case WasmOpcode_f32_ceil: function = "ceilf"; break;
1582 case WasmOpcode_f32_floor: function = "floorf"; break;
1583 case WasmOpcode_f32_trunc: function = "truncf"; break;
1584 case WasmOpcode_f32_nearest: function = "roundf"; break;
1585 case WasmOpcode_f32_sqrt: function = "sqrtf"; break;
1586 case WasmOpcode_f64_abs: function = "fabs"; break;
1587 case WasmOpcode_f64_ceil: function = "ceil"; break;
1588 case WasmOpcode_f64_floor: function = "floor"; break;
1589 case WasmOpcode_f64_trunc: function = "trunc"; break;
1590 case WasmOpcode_f64_nearest: function = "round"; break;
1591 case WasmOpcode_f64_sqrt: function = "sqrt"; break;
1592 default: panic("unreachable");
1593 }
1594 FuncGen_indent(&fg, out);
1595 fprintf(out, "l%" PRIu32 " = %s(l%" PRIu32 ");\n", lhs, function, lhs);
14951596 }
14961597 break;
1497 case WasmOpcode_i64_gt_s:
1598 case WasmOpcode_i32_add:
1599 case WasmOpcode_i32_sub:
1600 case WasmOpcode_i32_mul:
1601 case WasmOpcode_i32_div_u:
1602 case WasmOpcode_i32_rem_u:
1603 case WasmOpcode_i32_and:
1604 case WasmOpcode_i32_or:
1605 case WasmOpcode_i32_xor:
1606 case WasmOpcode_i64_add:
1607 case WasmOpcode_i64_sub:
1608 case WasmOpcode_i64_mul:
1609 case WasmOpcode_i64_div_u:
1610 case WasmOpcode_i64_rem_u:
1611 case WasmOpcode_i64_and:
1612 case WasmOpcode_i64_or:
1613 case WasmOpcode_i64_xor:
1614 case WasmOpcode_f32_add:
1615 case WasmOpcode_f32_sub:
1616 case WasmOpcode_f32_mul:
1617 case WasmOpcode_f32_div:
1618 case WasmOpcode_f64_add:
1619 case WasmOpcode_f64_sub:
1620 case WasmOpcode_f64_mul:
1621 case WasmOpcode_f64_div:
1622 // unsigned binary operators
14981623 if (unreachable_depth == 0) {
14991624 uint32_t rhs = FuncGen_stackPop(&fg);
1500 uint32_t lhs = FuncGen_stackPop(&fg);
1501 FuncGen_stackPush(&fg, out, WasmValType_i32);
1502 fprintf(out, "(int64_t)l%" PRIu32 " > (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1625 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1626 char operator;
1627 switch (opcode) {
1628 case WasmOpcode_i32_add:
1629 case WasmOpcode_i64_add:
1630 case WasmOpcode_f32_add:
1631 case WasmOpcode_f64_add:
1632 operator = '+';
1633 break;
1634 case WasmOpcode_i32_sub:
1635 case WasmOpcode_i64_sub:
1636 case WasmOpcode_f32_sub:
1637 case WasmOpcode_f64_sub:
1638 operator = '-';
1639 break;
1640 case WasmOpcode_i32_mul:
1641 case WasmOpcode_i64_mul:
1642 case WasmOpcode_f32_mul:
1643 case WasmOpcode_f64_mul:
1644 operator = '*';
1645 break;
1646 case WasmOpcode_i32_div_u:
1647 case WasmOpcode_i64_div_u:
1648 case WasmOpcode_f32_div:
1649 case WasmOpcode_f64_div:
1650 operator = '/';
1651 break;
1652 case WasmOpcode_i32_rem_u:
1653 case WasmOpcode_i64_rem_u:
1654 operator = '%';
1655 break;
1656 case WasmOpcode_i32_and:
1657 case WasmOpcode_i64_and:
1658 operator = '&';
1659 break;
1660 case WasmOpcode_i32_or:
1661 case WasmOpcode_i64_or:
1662 operator = '|';
1663 break;
1664 case WasmOpcode_i32_xor:
1665 case WasmOpcode_i64_xor:
1666 operator = '^';
1667 break;
1668 default: panic("unreachable");
1669 }
1670 FuncGen_indent(&fg, out);
1671 fprintf(out, "l%" PRIu32 " %c= l%" PRIu32 ";\n", lhs, operator, rhs);
15031672 }
15041673 break;
1505 case WasmOpcode_i64_gt_u:
1674 case WasmOpcode_i32_div_s:
1675 case WasmOpcode_i32_rem_s:
1676 case WasmOpcode_i64_div_s:
1677 case WasmOpcode_i64_rem_s:
1678 // signed binary operators
15061679 if (unreachable_depth == 0) {
15071680 uint32_t rhs = FuncGen_stackPop(&fg);
1508 uint32_t lhs = FuncGen_stackPop(&fg);
1509 FuncGen_stackPush(&fg, out, WasmValType_i32);
1510 fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
1681 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1682 char operator;
1683 unsigned width;
1684 switch (opcode) {
1685 case WasmOpcode_i32_div_s:
1686 case WasmOpcode_i64_div_s:
1687 operator = '/';
1688 break;
1689 case WasmOpcode_i32_rem_s:
1690 case WasmOpcode_i64_rem_s:
1691 operator = '%';
1692 break;
1693 default: panic("unreachable");
1694 }
1695 switch (opcode) {
1696 case WasmOpcode_i32_div_s:
1697 case WasmOpcode_i32_rem_s:
1698 width = 32;
1699 break;
1700 case WasmOpcode_i64_div_s:
1701 case WasmOpcode_i64_rem_s:
1702 width = 64;
1703 break;
1704 default: panic("unreachable");
1705 }
1706 FuncGen_indent(&fg, out);
1707 fprintf(out, "l%" PRIu32 " = (uint%u_t)((int%u_t)l%" PRIu32 " %c "
1708 "(int%u_t)l%" PRIu32 ");\n",
1709 lhs, width, width, lhs, operator, width, rhs);
15111710 }
15121711 break;
1513 case WasmOpcode_i64_le_s:
1712 case WasmOpcode_i32_shl:
1713 case WasmOpcode_i32_shr_u:
1714 case WasmOpcode_i64_shl:
1715 case WasmOpcode_i64_shr_u:
1716 // unsigned shift operators
15141717 if (unreachable_depth == 0) {
15151718 uint32_t rhs = FuncGen_stackPop(&fg);
1516 uint32_t lhs = FuncGen_stackPop(&fg);
1517 FuncGen_stackPush(&fg, out, WasmValType_i32);
1518 fprintf(out, "(int64_t)l%" PRIu32 " <= (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1719 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1720 char operator;
1721 unsigned width;
1722 switch (opcode) {
1723 case WasmOpcode_i32_shl:
1724 case WasmOpcode_i64_shl:
1725 operator = '<';
1726 break;
1727 case WasmOpcode_i32_shr_u:
1728 case WasmOpcode_i64_shr_u:
1729 operator = '>';
1730 break;
1731 default: panic("unreachable");
1732 }
1733 switch (opcode) {
1734 case WasmOpcode_i32_shl:
1735 case WasmOpcode_i32_shr_u:
1736 width = 32;
1737 break;
1738 case WasmOpcode_i64_shl:
1739 case WasmOpcode_i64_shr_u:
1740 width = 64;
1741 break;
1742 default: panic("unreachable");
1743 }
1744 FuncGen_indent(&fg, out);
1745 fprintf(out, "l%" PRIu32 " %c%c= l%" PRIu32 " & 0x%X;\n",
1746 lhs, operator, operator, rhs, width - 1);
15191747 }
15201748 break;
1521 case WasmOpcode_i64_le_u:
1749 case WasmOpcode_i32_shr_s:
1750 case WasmOpcode_i64_shr_s:
1751 // signed shift operators
15221752 if (unreachable_depth == 0) {
15231753 uint32_t rhs = FuncGen_stackPop(&fg);
1524 uint32_t lhs = FuncGen_stackPop(&fg);
1525 FuncGen_stackPush(&fg, out, WasmValType_i32);
1526 fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
1754 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1755 char operator;
1756 unsigned width;
1757 switch (opcode) {
1758 case WasmOpcode_i32_shr_s:
1759 case WasmOpcode_i64_shr_s:
1760 operator = '>';
1761 break;
1762 default: panic("unreachable");
1763 }
1764 switch (opcode) {
1765 case WasmOpcode_i32_shr_s:
1766 width = 32;
1767 break;
1768 case WasmOpcode_i64_shr_s:
1769 width = 64;
1770 break;
1771 default: panic("unreachable");
1772 }
1773 FuncGen_indent(&fg, out);
1774 fprintf(out, "l%" PRIu32 " = (uint%u_t)((int%u_t)l%" PRIu32 " %c%c "
1775 "(l%" PRIu32 " & 0x%X));\n",
1776 lhs, width, width, lhs, operator, operator, rhs, width - 1);
15271777 }
15281778 break;
1529 case WasmOpcode_i64_ge_s:
1779 case WasmOpcode_i32_rotl:
1780 case WasmOpcode_i32_rotr:
1781 case WasmOpcode_i64_rotl:
1782 case WasmOpcode_i64_rotr:
1783 // rotate operators
15301784 if (unreachable_depth == 0) {
15311785 uint32_t rhs = FuncGen_stackPop(&fg);
1532 uint32_t lhs = FuncGen_stackPop(&fg);
1533 FuncGen_stackPush(&fg, out, WasmValType_i32);
1534 fprintf(out, "(int64_t)l%" PRIu32 " >= (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1786 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1787 char forward_operator;
1788 char reverse_operator;
1789 unsigned width;
1790 switch (opcode) {
1791 case WasmOpcode_i32_rotl:
1792 case WasmOpcode_i64_rotl:
1793 forward_operator = '<';
1794 reverse_operator = '>';
1795 break;
1796 case WasmOpcode_i32_rotr:
1797 case WasmOpcode_i64_rotr:
1798 forward_operator = '>';
1799 reverse_operator = '<';
1800 break;
1801 default: panic("unreachable");
1802 }
1803 switch (opcode) {
1804 case WasmOpcode_i32_rotl:
1805 case WasmOpcode_i32_rotr:
1806 width = 32;
1807 break;
1808 case WasmOpcode_i64_rotl:
1809 case WasmOpcode_i64_rotr:
1810 width = 64;
1811 break;
1812 default: panic("unreachable");
1813 }
1814 FuncGen_indent(&fg, out);
1815 fprintf(out, "l%" PRIu32" = l%" PRIu32 " %c%c (l%" PRIu32 " & 0x%X) | "
1816 "l%" PRIu32 " %c%c (-l%" PRIu32" & 0x%X);\n", lhs,
1817 lhs, forward_operator, forward_operator, rhs, width - 1,
1818 lhs, reverse_operator, reverse_operator, rhs, width - 1);
15351819 }
15361820 break;
1537 case WasmOpcode_i64_ge_u:
1821 case WasmOpcode_f32_min:
1822 case WasmOpcode_f32_max:
1823 case WasmOpcode_f32_copysign:
1824 case WasmOpcode_f64_min:
1825 case WasmOpcode_f64_max:
1826 case WasmOpcode_f64_copysign:
1827 // binary functions
15381828 if (unreachable_depth == 0) {
15391829 uint32_t rhs = FuncGen_stackPop(&fg);
1540 uint32_t lhs = FuncGen_stackPop(&fg);
1541 FuncGen_stackPush(&fg, out, WasmValType_i32);
1542 fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
1543 }
1544 break;
1545
1546 case WasmOpcode_f32_eq:
1547 if (unreachable_depth == 0) {
1548 uint32_t rhs = FuncGen_stackPop(&fg);
1549 uint32_t lhs = FuncGen_stackPop(&fg);
1550 FuncGen_stackPush(&fg, out, WasmValType_i32);
1551 fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
1552 }
1553 break;
1554 case WasmOpcode_f32_ne:
1555 if (unreachable_depth == 0) {
1556 uint32_t rhs = FuncGen_stackPop(&fg);
1557 uint32_t lhs = FuncGen_stackPop(&fg);
1558 FuncGen_stackPush(&fg, out, WasmValType_i32);
1559 fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
1560 }
1561 break;
1562 case WasmOpcode_f32_lt:
1563 if (unreachable_depth == 0) {
1564 uint32_t rhs = FuncGen_stackPop(&fg);
1565 uint32_t lhs = FuncGen_stackPop(&fg);
1566 FuncGen_stackPush(&fg, out, WasmValType_i32);
1567 fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
1568 }
1569 break;
1570 case WasmOpcode_f32_gt:
1571 if (unreachable_depth == 0) {
1572 uint32_t rhs = FuncGen_stackPop(&fg);
1573 uint32_t lhs = FuncGen_stackPop(&fg);
1574 FuncGen_stackPush(&fg, out, WasmValType_i32);
1575 fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
1576 }
1577 break;
1578 case WasmOpcode_f32_le:
1579 if (unreachable_depth == 0) {
1580 uint32_t rhs = FuncGen_stackPop(&fg);
1581 uint32_t lhs = FuncGen_stackPop(&fg);
1582 FuncGen_stackPush(&fg, out, WasmValType_i32);
1583 fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
1584 }
1585 break;
1586 case WasmOpcode_f32_ge:
1587 if (unreachable_depth == 0) {
1588 uint32_t rhs = FuncGen_stackPop(&fg);
1589 uint32_t lhs = FuncGen_stackPop(&fg);
1590 FuncGen_stackPush(&fg, out, WasmValType_i32);
1591 fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
1592 }
1593 break;
1594
1595 case WasmOpcode_f64_eq:
1596 if (unreachable_depth == 0) {
1597 uint32_t rhs = FuncGen_stackPop(&fg);
1598 uint32_t lhs = FuncGen_stackPop(&fg);
1599 FuncGen_stackPush(&fg, out, WasmValType_i32);
1600 fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
1601 }
1602 break;
1603 case WasmOpcode_f64_ne:
1604 if (unreachable_depth == 0) {
1605 uint32_t rhs = FuncGen_stackPop(&fg);
1606 uint32_t lhs = FuncGen_stackPop(&fg);
1607 FuncGen_stackPush(&fg, out, WasmValType_i32);
1608 fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
1609 }
1610 break;
1611 case WasmOpcode_f64_lt:
1612 if (unreachable_depth == 0) {
1613 uint32_t rhs = FuncGen_stackPop(&fg);
1614 uint32_t lhs = FuncGen_stackPop(&fg);
1615 FuncGen_stackPush(&fg, out, WasmValType_i32);
1616 fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
1617 }
1618 break;
1619 case WasmOpcode_f64_gt:
1620 if (unreachable_depth == 0) {
1621 uint32_t rhs = FuncGen_stackPop(&fg);
1622 uint32_t lhs = FuncGen_stackPop(&fg);
1623 FuncGen_stackPush(&fg, out, WasmValType_i32);
1624 fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
1625 }
1626 break;
1627 case WasmOpcode_f64_le:
1628 if (unreachable_depth == 0) {
1629 uint32_t rhs = FuncGen_stackPop(&fg);
1630 uint32_t lhs = FuncGen_stackPop(&fg);
1631 FuncGen_stackPush(&fg, out, WasmValType_i32);
1632 fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
1633 }
1634 break;
1635 case WasmOpcode_f64_ge:
1636 if (unreachable_depth == 0) {
1637 uint32_t rhs = FuncGen_stackPop(&fg);
1638 uint32_t lhs = FuncGen_stackPop(&fg);
1639 FuncGen_stackPush(&fg, out, WasmValType_i32);
1640 fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
1641 }
1642 break;
1643
1644 case WasmOpcode_i32_clz:
1645 if (unreachable_depth == 0) {
1646 uint32_t lhs = FuncGen_stackPop(&fg);
1647 FuncGen_stackPush(&fg, out, WasmValType_i32);
1648 fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clz(l%" PRIu32 ") : 32;\n",
1649 lhs, lhs);
1650 }
1651 break;
1652 case WasmOpcode_i32_ctz:
1653 if (unreachable_depth == 0) {
1654 uint32_t lhs = FuncGen_stackPop(&fg);
1655 FuncGen_stackPush(&fg, out, WasmValType_i32);
1656 fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctz(l%" PRIu32 ") : 32;\n",
1657 lhs, lhs);
1658 }
1659 break;
1660 case WasmOpcode_i32_popcnt:
1661 if (unreachable_depth == 0) {
1662 uint32_t lhs = FuncGen_stackPop(&fg);
1663 FuncGen_stackPush(&fg, out, WasmValType_i32);
1664 fprintf(out, "__builtin_popcount(l%" PRIu32 ");\n", lhs);
1665 }
1666 break;
1667 case WasmOpcode_i32_add:
1668 if (unreachable_depth == 0) {
1669 uint32_t rhs = FuncGen_stackPop(&fg);
1670 uint32_t lhs = FuncGen_stackPop(&fg);
1671 FuncGen_stackPush(&fg, out, WasmValType_i32);
1672 fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
1673 }
1674 break;
1675 case WasmOpcode_i32_sub:
1676 if (unreachable_depth == 0) {
1677 uint32_t rhs = FuncGen_stackPop(&fg);
1678 uint32_t lhs = FuncGen_stackPop(&fg);
1679 FuncGen_stackPush(&fg, out, WasmValType_i32);
1680 fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
1681 }
1682 break;
1683 case WasmOpcode_i32_mul:
1684 if (unreachable_depth == 0) {
1685 uint32_t rhs = FuncGen_stackPop(&fg);
1686 uint32_t lhs = FuncGen_stackPop(&fg);
1687 FuncGen_stackPush(&fg, out, WasmValType_i32);
1688 fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
1689 }
1690 break;
1691 case WasmOpcode_i32_div_s:
1692 if (unreachable_depth == 0) {
1693 uint32_t rhs = FuncGen_stackPop(&fg);
1694 uint32_t lhs = FuncGen_stackPop(&fg);
1695 FuncGen_stackPush(&fg, out, WasmValType_i32);
1696 fprintf(out, "(int32_t)l%" PRIu32 " / (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1697 }
1698 break;
1699 case WasmOpcode_i32_div_u:
1700 if (unreachable_depth == 0) {
1701 uint32_t rhs = FuncGen_stackPop(&fg);
1702 uint32_t lhs = FuncGen_stackPop(&fg);
1703 FuncGen_stackPush(&fg, out, WasmValType_i32);
1704 fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
1705 }
1706 break;
1707 case WasmOpcode_i32_rem_s:
1708 if (unreachable_depth == 0) {
1709 uint32_t rhs = FuncGen_stackPop(&fg);
1710 uint32_t lhs = FuncGen_stackPop(&fg);
1711 FuncGen_stackPush(&fg, out, WasmValType_i32);
1712 fprintf(out, "(int32_t)l%" PRIu32 " %% (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1713 }
1714 break;
1715 case WasmOpcode_i32_rem_u:
1716 if (unreachable_depth == 0) {
1717 uint32_t rhs = FuncGen_stackPop(&fg);
1718 uint32_t lhs = FuncGen_stackPop(&fg);
1719 FuncGen_stackPush(&fg, out, WasmValType_i32);
1720 fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs);
1721 }
1722 break;
1723 case WasmOpcode_i32_and:
1724 if (unreachable_depth == 0) {
1725 uint32_t rhs = FuncGen_stackPop(&fg);
1726 uint32_t lhs = FuncGen_stackPop(&fg);
1727 FuncGen_stackPush(&fg, out, WasmValType_i32);
1728 fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs);
1729 }
1730 break;
1731 case WasmOpcode_i32_or:
1732 if (unreachable_depth == 0) {
1733 uint32_t rhs = FuncGen_stackPop(&fg);
1734 uint32_t lhs = FuncGen_stackPop(&fg);
1735 FuncGen_stackPush(&fg, out, WasmValType_i32);
1736 fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs);
1737 }
1738 break;
1739 case WasmOpcode_i32_xor:
1740 if (unreachable_depth == 0) {
1741 uint32_t rhs = FuncGen_stackPop(&fg);
1742 uint32_t lhs = FuncGen_stackPop(&fg);
1743 FuncGen_stackPush(&fg, out, WasmValType_i32);
1744 fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs);
1745 }
1746 break;
1747 case WasmOpcode_i32_shl:
1748 if (unreachable_depth == 0) {
1749 uint32_t rhs = FuncGen_stackPop(&fg);
1750 uint32_t lhs = FuncGen_stackPop(&fg);
1751 FuncGen_stackPush(&fg, out, WasmValType_i32);
1752 fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F);\n", lhs, rhs);
1753 }
1754 break;
1755 case WasmOpcode_i32_shr_s:
1756 if (unreachable_depth == 0) {
1757 uint32_t rhs = FuncGen_stackPop(&fg);
1758 uint32_t lhs = FuncGen_stackPop(&fg);
1759 FuncGen_stackPush(&fg, out, WasmValType_i32);
1760 fprintf(out, "(int32_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs);
1761 }
1762 break;
1763 case WasmOpcode_i32_shr_u:
1764 if (unreachable_depth == 0) {
1765 uint32_t rhs = FuncGen_stackPop(&fg);
1766 uint32_t lhs = FuncGen_stackPop(&fg);
1767 FuncGen_stackPush(&fg, out, WasmValType_i32);
1768 fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs);
1769 }
1770 break;
1771 case WasmOpcode_i32_rotl:
1772 if (unreachable_depth == 0) {
1773 uint32_t rhs = FuncGen_stackPop(&fg);
1774 uint32_t lhs = FuncGen_stackPop(&fg);
1775 FuncGen_stackPush(&fg, out, WasmValType_i32);
1776 fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F) | "
1777 "l%" PRIu32 " >> (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs);
1778 }
1779 break;
1780 case WasmOpcode_i32_rotr:
1781 if (unreachable_depth == 0) {
1782 uint32_t rhs = FuncGen_stackPop(&fg);
1783 uint32_t lhs = FuncGen_stackPop(&fg);
1784 FuncGen_stackPush(&fg, out, WasmValType_i32);
1785 fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F) | "
1786 "l%" PRIu32 " << (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs);
1787 }
1788 break;
1789
1790 case WasmOpcode_i64_clz:
1791 if (unreachable_depth == 0) {
1792 uint32_t lhs = FuncGen_stackPop(&fg);
1793 FuncGen_stackPush(&fg, out, WasmValType_i64);
1794 fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clzll(l%" PRIu32 ") : 64;\n",
1795 lhs, lhs);
1796 }
1797 break;
1798 case WasmOpcode_i64_ctz:
1799 if (unreachable_depth == 0) {
1800 uint32_t lhs = FuncGen_stackPop(&fg);
1801 FuncGen_stackPush(&fg, out, WasmValType_i64);
1802 fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctzll(l%" PRIu32 ") : 64;\n",
1803 lhs, lhs);
1804 }
1805 break;
1806 case WasmOpcode_i64_popcnt:
1807 if (unreachable_depth == 0) {
1808 uint32_t lhs = FuncGen_stackPop(&fg);
1809 FuncGen_stackPush(&fg, out, WasmValType_i64);
1810 fprintf(out, "__builtin_popcountll(l%" PRIu32 ");\n", lhs);
1811 }
1812 break;
1813 case WasmOpcode_i64_add:
1814 if (unreachable_depth == 0) {
1815 uint32_t rhs = FuncGen_stackPop(&fg);
1816 uint32_t lhs = FuncGen_stackPop(&fg);
1817 FuncGen_stackPush(&fg, out, WasmValType_i64);
1818 fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
1819 }
1820 break;
1821 case WasmOpcode_i64_sub:
1822 if (unreachable_depth == 0) {
1823 uint32_t rhs = FuncGen_stackPop(&fg);
1824 uint32_t lhs = FuncGen_stackPop(&fg);
1825 FuncGen_stackPush(&fg, out, WasmValType_i64);
1826 fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
1827 }
1828 break;
1829 case WasmOpcode_i64_mul:
1830 if (unreachable_depth == 0) {
1831 uint32_t rhs = FuncGen_stackPop(&fg);
1832 uint32_t lhs = FuncGen_stackPop(&fg);
1833 FuncGen_stackPush(&fg, out, WasmValType_i64);
1834 fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
1835 }
1836 break;
1837 case WasmOpcode_i64_div_s:
1838 if (unreachable_depth == 0) {
1839 uint32_t rhs = FuncGen_stackPop(&fg);
1840 uint32_t lhs = FuncGen_stackPop(&fg);
1841 FuncGen_stackPush(&fg, out, WasmValType_i64);
1842 fprintf(out, "(int64_t)l%" PRIu32 " / (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1843 }
1844 break;
1845 case WasmOpcode_i64_div_u:
1846 if (unreachable_depth == 0) {
1847 uint32_t rhs = FuncGen_stackPop(&fg);
1848 uint32_t lhs = FuncGen_stackPop(&fg);
1849 FuncGen_stackPush(&fg, out, WasmValType_i64);
1850 fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
1851 }
1852 break;
1853 case WasmOpcode_i64_rem_s:
1854 if (unreachable_depth == 0) {
1855 uint32_t rhs = FuncGen_stackPop(&fg);
1856 uint32_t lhs = FuncGen_stackPop(&fg);
1857 FuncGen_stackPush(&fg, out, WasmValType_i64);
1858 fprintf(out, "(int64_t)l%" PRIu32 " %% (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1859 }
1860 break;
1861 case WasmOpcode_i64_rem_u:
1862 if (unreachable_depth == 0) {
1863 uint32_t rhs = FuncGen_stackPop(&fg);
1864 uint32_t lhs = FuncGen_stackPop(&fg);
1865 FuncGen_stackPush(&fg, out, WasmValType_i64);
1866 fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs);
1867 }
1868 break;
1869 case WasmOpcode_i64_and:
1870 if (unreachable_depth == 0) {
1871 uint32_t rhs = FuncGen_stackPop(&fg);
1872 uint32_t lhs = FuncGen_stackPop(&fg);
1873 FuncGen_stackPush(&fg, out, WasmValType_i64);
1874 fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs);
1875 }
1876 break;
1877 case WasmOpcode_i64_or:
1878 if (unreachable_depth == 0) {
1879 uint32_t rhs = FuncGen_stackPop(&fg);
1880 uint32_t lhs = FuncGen_stackPop(&fg);
1881 FuncGen_stackPush(&fg, out, WasmValType_i64);
1882 fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs);
1883 }
1884 break;
1885 case WasmOpcode_i64_xor:
1886 if (unreachable_depth == 0) {
1887 uint32_t rhs = FuncGen_stackPop(&fg);
1888 uint32_t lhs = FuncGen_stackPop(&fg);
1889 FuncGen_stackPush(&fg, out, WasmValType_i64);
1890 fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs);
1891 }
1892 break;
1893 case WasmOpcode_i64_shl:
1894 if (unreachable_depth == 0) {
1895 uint32_t rhs = FuncGen_stackPop(&fg);
1896 uint32_t lhs = FuncGen_stackPop(&fg);
1897 FuncGen_stackPush(&fg, out, WasmValType_i64);
1898 fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F);\n", lhs, rhs);
1899 }
1900 break;
1901 case WasmOpcode_i64_shr_s:
1902 if (unreachable_depth == 0) {
1903 uint32_t rhs = FuncGen_stackPop(&fg);
1904 uint32_t lhs = FuncGen_stackPop(&fg);
1905 FuncGen_stackPush(&fg, out, WasmValType_i64);
1906 fprintf(out, "(int64_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs);
1907 }
1908 break;
1909 case WasmOpcode_i64_shr_u:
1910 if (unreachable_depth == 0) {
1911 uint32_t rhs = FuncGen_stackPop(&fg);
1912 uint32_t lhs = FuncGen_stackPop(&fg);
1913 FuncGen_stackPush(&fg, out, WasmValType_i64);
1914 fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs);
1915 }
1916 break;
1917 case WasmOpcode_i64_rotl:
1918 if (unreachable_depth == 0) {
1919 uint32_t rhs = FuncGen_stackPop(&fg);
1920 uint32_t lhs = FuncGen_stackPop(&fg);
1921 FuncGen_stackPush(&fg, out, WasmValType_i64);
1922 fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F) | "
1923 "l%" PRIu32 " >> (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs);
1924 }
1925 break;
1926 case WasmOpcode_i64_rotr:
1927 if (unreachable_depth == 0) {
1928 uint32_t rhs = FuncGen_stackPop(&fg);
1929 uint32_t lhs = FuncGen_stackPop(&fg);
1930 FuncGen_stackPush(&fg, out, WasmValType_i64);
1931 fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F) | "
1932 "l%" PRIu32 " << (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs);
1933 }
1934 break;
1935
1936 case WasmOpcode_f32_abs:
1937 if (unreachable_depth == 0) {
1938 uint32_t lhs = FuncGen_stackPop(&fg);
1939 FuncGen_stackPush(&fg, out, WasmValType_f32);
1940 fprintf(out, "fabsf(l%" PRIu32 ");\n", lhs);
1941 }
1942 break;
1943 case WasmOpcode_f32_neg:
1944 if (unreachable_depth == 0) {
1945 uint32_t lhs = FuncGen_stackPop(&fg);
1946 FuncGen_stackPush(&fg, out, WasmValType_f32);
1947 fprintf(out, "-l%" PRIu32 ";\n", lhs);
1948 }
1949 break;
1950 case WasmOpcode_f32_ceil:
1951 if (unreachable_depth == 0) {
1952 uint32_t lhs = FuncGen_stackPop(&fg);
1953 FuncGen_stackPush(&fg, out, WasmValType_f32);
1954 fprintf(out, "ceilf(l%" PRIu32 ");\n", lhs);
1955 }
1956 break;
1957 case WasmOpcode_f32_floor:
1958 if (unreachable_depth == 0) {
1959 uint32_t lhs = FuncGen_stackPop(&fg);
1960 FuncGen_stackPush(&fg, out, WasmValType_f32);
1961 fprintf(out, "floorf(l%" PRIu32 ");\n", lhs);
1962 }
1963 break;
1964 case WasmOpcode_f32_trunc:
1965 if (unreachable_depth == 0) {
1966 uint32_t lhs = FuncGen_stackPop(&fg);
1967 FuncGen_stackPush(&fg, out, WasmValType_f32);
1968 fprintf(out, "truncf(l%" PRIu32 ");\n", lhs);
1969 }
1970 break;
1971 case WasmOpcode_f32_nearest:
1972 if (unreachable_depth == 0) {
1973 uint32_t lhs = FuncGen_stackPop(&fg);
1974 FuncGen_stackPush(&fg, out, WasmValType_f32);
1975 fprintf(out, "roundf(l%" PRIu32 ");\n", lhs);
1976 }
1977 break;
1978 case WasmOpcode_f32_sqrt:
1979 if (unreachable_depth == 0) {
1980 uint32_t lhs = FuncGen_stackPop(&fg);
1981 FuncGen_stackPush(&fg, out, WasmValType_f32);
1982 fprintf(out, "sqrtf(l%" PRIu32 ");\n", lhs);
1983 }
1984 break;
1985 case WasmOpcode_f32_add:
1986 if (unreachable_depth == 0) {
1987 uint32_t rhs = FuncGen_stackPop(&fg);
1988 uint32_t lhs = FuncGen_stackPop(&fg);
1989 FuncGen_stackPush(&fg, out, WasmValType_f32);
1990 fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
1991 }
1992 break;
1993 case WasmOpcode_f32_sub:
1994 if (unreachable_depth == 0) {
1995 uint32_t rhs = FuncGen_stackPop(&fg);
1996 uint32_t lhs = FuncGen_stackPop(&fg);
1997 FuncGen_stackPush(&fg, out, WasmValType_f32);
1998 fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
1999 }
2000 break;
2001 case WasmOpcode_f32_mul:
2002 if (unreachable_depth == 0) {
2003 uint32_t rhs = FuncGen_stackPop(&fg);
2004 uint32_t lhs = FuncGen_stackPop(&fg);
2005 FuncGen_stackPush(&fg, out, WasmValType_f32);
2006 fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
2007 }
2008 break;
2009 case WasmOpcode_f32_div:
2010 if (unreachable_depth == 0) {
2011 uint32_t rhs = FuncGen_stackPop(&fg);
2012 uint32_t lhs = FuncGen_stackPop(&fg);
2013 FuncGen_stackPush(&fg, out, WasmValType_f32);
2014 fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
2015 }
2016 break;
2017 case WasmOpcode_f32_min:
2018 if (unreachable_depth == 0) {
2019 uint32_t rhs = FuncGen_stackPop(&fg);
2020 uint32_t lhs = FuncGen_stackPop(&fg);
2021 FuncGen_stackPush(&fg, out, WasmValType_f32);
2022 fprintf(out, "fminf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2023 }
2024 break;
2025 case WasmOpcode_f32_max:
2026 if (unreachable_depth == 0) {
2027 uint32_t rhs = FuncGen_stackPop(&fg);
2028 uint32_t lhs = FuncGen_stackPop(&fg);
2029 FuncGen_stackPush(&fg, out, WasmValType_f32);
2030 fprintf(out, "fmaxf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2031 }
2032 break;
2033 case WasmOpcode_f32_copysign:
2034 if (unreachable_depth == 0) {
2035 uint32_t rhs = FuncGen_stackPop(&fg);
2036 uint32_t lhs = FuncGen_stackPop(&fg);
2037 FuncGen_stackPush(&fg, out, WasmValType_f32);
2038 fprintf(out, "copysignf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2039 }
2040 break;
2041
2042 case WasmOpcode_f64_abs:
2043 if (unreachable_depth == 0) {
2044 uint32_t lhs = FuncGen_stackPop(&fg);
2045 FuncGen_stackPush(&fg, out, WasmValType_f64);
2046 fprintf(out, "fabs(l%" PRIu32 ");\n", lhs);
2047 }
2048 break;
2049 case WasmOpcode_f64_neg:
2050 if (unreachable_depth == 0) {
2051 uint32_t lhs = FuncGen_stackPop(&fg);
2052 FuncGen_stackPush(&fg, out, WasmValType_f64);
2053 fprintf(out, "-l%" PRIu32 ";\n", lhs);
2054 }
2055 break;
2056 case WasmOpcode_f64_ceil:
2057 if (unreachable_depth == 0) {
2058 uint32_t lhs = FuncGen_stackPop(&fg);
2059 FuncGen_stackPush(&fg, out, WasmValType_f64);
2060 fprintf(out, "ceil(l%" PRIu32 ");\n", lhs);
2061 }
2062 break;
2063 case WasmOpcode_f64_floor:
2064 if (unreachable_depth == 0) {
2065 uint32_t lhs = FuncGen_stackPop(&fg);
2066 FuncGen_stackPush(&fg, out, WasmValType_f64);
2067 fprintf(out, "floor(l%" PRIu32 ");\n", lhs);
2068 }
2069 break;
2070 case WasmOpcode_f64_trunc:
2071 if (unreachable_depth == 0) {
2072 uint32_t lhs = FuncGen_stackPop(&fg);
2073 FuncGen_stackPush(&fg, out, WasmValType_f64);
2074 fprintf(out, "trunc(l%" PRIu32 ");\n", lhs);
2075 }
2076 break;
2077 case WasmOpcode_f64_nearest:
2078 if (unreachable_depth == 0) {
2079 uint32_t lhs = FuncGen_stackPop(&fg);
2080 FuncGen_stackPush(&fg, out, WasmValType_f64);
2081 fprintf(out, "round(l%" PRIu32 ");\n", lhs);
2082 }
2083 break;
2084 case WasmOpcode_f64_sqrt:
2085 if (unreachable_depth == 0) {
2086 uint32_t lhs = FuncGen_stackPop(&fg);
2087 FuncGen_stackPush(&fg, out, WasmValType_f64);
2088 fprintf(out, "sqrt(l%" PRIu32 ");\n", lhs);
2089 }
2090 break;
2091 case WasmOpcode_f64_add:
2092 if (unreachable_depth == 0) {
2093 uint32_t rhs = FuncGen_stackPop(&fg);
2094 uint32_t lhs = FuncGen_stackPop(&fg);
2095 FuncGen_stackPush(&fg, out, WasmValType_f64);
2096 fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
2097 }
2098 break;
2099 case WasmOpcode_f64_sub:
2100 if (unreachable_depth == 0) {
2101 uint32_t rhs = FuncGen_stackPop(&fg);
2102 uint32_t lhs = FuncGen_stackPop(&fg);
2103 FuncGen_stackPush(&fg, out, WasmValType_f64);
2104 fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
2105 }
2106 break;
2107 case WasmOpcode_f64_mul:
2108 if (unreachable_depth == 0) {
2109 uint32_t rhs = FuncGen_stackPop(&fg);
2110 uint32_t lhs = FuncGen_stackPop(&fg);
2111 FuncGen_stackPush(&fg, out, WasmValType_f64);
2112 fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
2113 }
2114 break;
2115 case WasmOpcode_f64_div:
2116 if (unreachable_depth == 0) {
2117 uint32_t rhs = FuncGen_stackPop(&fg);
2118 uint32_t lhs = FuncGen_stackPop(&fg);
2119 FuncGen_stackPush(&fg, out, WasmValType_f64);
2120 fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
2121 }
2122 break;
2123 case WasmOpcode_f64_min:
2124 if (unreachable_depth == 0) {
2125 uint32_t rhs = FuncGen_stackPop(&fg);
2126 uint32_t lhs = FuncGen_stackPop(&fg);
2127 FuncGen_stackPush(&fg, out, WasmValType_f64);
2128 fprintf(out, "fmin(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2129 }
2130 break;
2131 case WasmOpcode_f64_max:
2132 if (unreachable_depth == 0) {
2133 uint32_t rhs = FuncGen_stackPop(&fg);
2134 uint32_t lhs = FuncGen_stackPop(&fg);
2135 FuncGen_stackPush(&fg, out, WasmValType_f64);
2136 fprintf(out, "fmax(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2137 }
2138 break;
2139 case WasmOpcode_f64_copysign:
2140 if (unreachable_depth == 0) {
2141 uint32_t rhs = FuncGen_stackPop(&fg);
2142 uint32_t lhs = FuncGen_stackPop(&fg);
2143 FuncGen_stackPush(&fg, out, WasmValType_f64);
2144 fprintf(out, "copysign(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
1830 uint32_t lhs = FuncGen_stackAt(&fg, 0);
1831 const char *function;
1832 switch (opcode) {
1833 case WasmOpcode_f32_min: function = "fminf"; break;
1834 case WasmOpcode_f32_max: function = "fmaxf"; break;
1835 case WasmOpcode_f32_copysign: function = "copysignf"; break;
1836 case WasmOpcode_f64_min: function = "fmin"; break;
1837 case WasmOpcode_f64_max: function = "fmax"; break;
1838 case WasmOpcode_f64_copysign: function = "copysign"; break;
1839 default: panic("unreachable");
1840 }
1841 FuncGen_indent(&fg, out);
1842 fprintf(out, "l%" PRIu32 " = %s(l%" PRIu32 ", l%" PRIu32 ");\n",
1843 lhs, function, lhs, rhs);
21451844 }
21461845 break;
21471846