diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-07-31 21:06:33 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-07-31 21:11:36 +0900 |
| commit | 43999492a792263eb234db1d399103471c39009c (patch) | |
| tree | 0bd832a03e5b80d0a718d97ee340d38fca189190 | |
| parent | 4306893971130edb31ac07d54c86923c2fbfa8c0 (diff) | |
| download | mruby-43999492a792263eb234db1d399103471c39009c.tar.gz mruby-43999492a792263eb234db1d399103471c39009c.zip | |
codegen.c: `mrb_prev_pc()` to take previous instruction position.
It rescans `s->iseq` so that peephole optimizer can take multiple
previous instructions for constant folding, etc.
| -rw-r--r-- | include/mruby/irep.h | 1 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 210 |
2 files changed, 132 insertions, 79 deletions
diff --git a/include/mruby/irep.h b/include/mruby/irep.h index aaf489933..2a0e261d1 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -123,6 +123,7 @@ struct mrb_insn_data { uint16_t a; uint16_t b; uint8_t c; + const mrb_code *addr; }; struct mrb_insn_data mrb_decode_insn(const mrb_code *pc); diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 51f71ba70..5a02f2d09 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -57,7 +57,6 @@ typedef struct scope { uint16_t sp; uint32_t pc; - uint32_t lastpc; uint32_t lastlabel; int ainfo:15; mrb_bool mscope:1; @@ -229,14 +228,12 @@ gen_S(codegen_scope *s, uint16_t i) static void genop_0(codegen_scope *s, mrb_code i) { - s->lastpc = s->pc; gen_B(s, i); } static void genop_1(codegen_scope *s, mrb_code i, uint16_t a) { - s->lastpc = s->pc; if (a > 0xff) { gen_B(s, OP_EXT1); gen_B(s, i); @@ -251,7 +248,6 @@ genop_1(codegen_scope *s, mrb_code i, uint16_t a) static void genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) { - s->lastpc = s->pc; if (a > 0xff && b > 0xff) { gen_B(s, OP_EXT3); gen_B(s, i); @@ -306,7 +302,6 @@ genop_W(codegen_scope *s, mrb_code i, uint32_t a) uint8_t a2 = (a>>8) & 0xff; uint8_t a3 = a & 0xff; - s->lastpc = s->pc; gen_B(s, i); gen_B(s, a1); gen_B(s, a2); @@ -328,6 +323,7 @@ struct mrb_insn_data mrb_decode_insn(const mrb_code *pc) { struct mrb_insn_data data = { 0 }; + data.addr = pc; mrb_code insn = READ_B(); uint16_t a = 0; uint16_t b = 0; @@ -374,22 +370,119 @@ mrb_decode_insn(const mrb_code *pc) return data; } +#undef OPCODE +#define Z 1 +#define S 3 +#define W 4 +#define OPCODE(_,x) x, +/* instruction sizes */ +static uint8_t mrb_insn_size[] = { +#define B 2 +#define BB 3 +#define BBB 4 +#define BS 4 +#define BSS 6 +#include "mruby/ops.h" +#undef B +#undef BB +#undef BBB +#undef BS +#undef BSS +}; +/* EXT1 instruction sizes */ +static uint8_t mrb_insn_size1[] = { +#define B 3 +#define BB 4 +#define BBB 5 +#define BS 5 +#define BSS 7 +#include "mruby/ops.h" +#undef B +#undef BS +#undef BSS +}; +/* EXT2 instruction sizes */ +static uint8_t mrb_insn_size2[] = { +#define B 2 +#define BS 4 +#define BSS 6 +#include "mruby/ops.h" +#undef B +#undef BB +#undef BBB +#undef BS +#undef BSS +}; +/* EXT3 instruction sizes */ +#define B 3 +#define BB 5 +#define BBB 6 +#define BS 5 +#define BSS 7 +static uint8_t mrb_insn_size3[] = { +#include "mruby/ops.h" +}; +#undef B +#undef BB +#undef BBB +#undef BS +#undef BSS +#undef OPCODE + +static const mrb_code* +mrb_prev_pc(codegen_scope *s, const mrb_code *pc) +{ + const mrb_code *prev_pc = NULL; + const mrb_code *i = s->iseq; + + while (i<pc) { + uint8_t insn = i[0]; + prev_pc = i; + switch (insn) { + case OP_EXT1: + i += mrb_insn_size1[i[1]] + 1; + break; + case OP_EXT2: + i += mrb_insn_size2[i[1]] + 1; + break; + case OP_EXT3: + i += mrb_insn_size3[i[1]] + 1; + break; + default: + i += mrb_insn_size[insn]; + break; + } + } + return prev_pc; +} + +#define pc_addr(s) &((s)->iseq[(s)->pc]) +#define addr_pc(s, addr) (uint32_t)((addr) - s->iseq) + +static void +rewind_pc(codegen_scope *s) +{ + const mrb_code *pc = mrb_prev_pc(s, pc_addr(s)); + s->pc = addr_pc(s, pc); +} + static struct mrb_insn_data mrb_last_insn(codegen_scope *s) { - if (s->pc == s->lastpc) { + const mrb_code *pc = mrb_prev_pc(s, pc_addr(s)); + if (pc == NULL) { struct mrb_insn_data data; data.insn = OP_NOP; return data; } - return mrb_decode_insn(&s->iseq[s->lastpc]); + return mrb_decode_insn(pc); } static mrb_bool no_peephole(codegen_scope *s) { - return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc; + return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0; } #define JMPLINK_START UINT32_MAX @@ -415,7 +508,6 @@ genjmp(codegen_scope *s, mrb_code i, uint32_t pc) { uint32_t pos; - s->lastpc = s->pc; gen_B(s, i); pos = s->pc; gen_jmpdst(s, pc); @@ -433,12 +525,11 @@ genjmp2(codegen_scope *s, mrb_code i, uint16_t a, uint32_t pc, int val) struct mrb_insn_data data = mrb_last_insn(s); if (data.insn == OP_MOVE && data.a == a) { - s->pc = s->lastpc; + rewind_pc(s); a = data.b; } } - s->lastpc = s->pc; if (a > 0xff) { gen_B(s, OP_EXT1); gen_B(s, i); @@ -477,7 +568,7 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: if (nopeep || data.a != src || data.a < s->nlocals) goto normal; - s->pc = s->lastpc; + rewind_pc(s); genop_1(s, data.insn, dst); break; case OP_LOADI: case OP_LOADINEG: case OP_LOADI16: @@ -486,19 +577,19 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) case OP_GETCONST: case OP_STRING: case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH: if (nopeep || data.a != src || data.a < s->nlocals) goto normal; - s->pc = s->lastpc; + rewind_pc(s); genop_2(s, data.insn, dst, data.b); break; case OP_GETUPVAR: if (nopeep || data.a != src || data.a < s->nlocals) goto normal; - s->pc = s->lastpc; + rewind_pc(s); genop_3(s, data.insn, dst, data.b, data.c); break; case OP_LOADI32: if (nopeep || data.a != src || data.a < s->nlocals) goto normal; else { uint32_t i = (uint32_t)data.b<<16|data.c; - s->pc = s->lastpc; + rewind_pc(s); genop_2SS(s, data.insn, dst, i); } break; @@ -533,7 +624,7 @@ gen_setupvar(codegen_scope *s, uint16_t dst, mrb_sym id) struct mrb_insn_data data = mrb_last_insn(s); if (!no_peephole(s) && data.insn == OP_MOVE && data.a == dst) { dst = data.b; - s->pc = s->lastpc; + rewind_pc(s); } genop_3(s, OP_SETUPVAR, dst, idx, lv); } @@ -548,7 +639,7 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src) struct mrb_insn_data data = mrb_last_insn(s); if (data.insn == OP_MOVE && src == data.a) { - s->pc = s->lastpc; + rewind_pc(s); genop_1(s, op, data.b); } else if (data.insn != OP_RETURN) { @@ -606,6 +697,8 @@ get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *n) } } +static void gen_int(codegen_scope *s, uint16_t dst, mrb_int i); + static void gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) { @@ -622,15 +715,27 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) /* not integer immediate */ goto normal; } - /* OP_ADDI/OP_SUBI takes upto 16bits */ - if (n > INT16_MAX) goto normal; - s->pc = s->lastpc; - if (op == OP_ADD) { - genop_2(s, OP_ADDI, dst, (uint16_t)n); + struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); + mrb_int n0; + if (addr_pc(s, data.addr) == s->lastlabel || !get_int_operand(s, &data0, &n0)) { + /* OP_ADDI/OP_SUBI takes upto 16bits */ + if (n > INT16_MAX) goto normal; + rewind_pc(s); + if (op == OP_ADD) { + genop_2(s, OP_ADDI, dst, (uint16_t)n); + } + else { + genop_2(s, OP_SUBI, dst, (uint16_t)n); + } + return; } - else { - genop_2(s, OP_SUBI, dst, (uint16_t)n); + if (op == OP_SUB) { + if (n == MRB_INT_MIN) goto normal; + n = -n; } + if (mrb_int_add_overflow(n0, n, &n)) goto normal; + s->pc = addr_pc(s, data0.addr); + gen_int(s, dst, n); } } @@ -860,7 +965,7 @@ gen_setxv(codegen_scope *s, uint8_t op, uint16_t dst, mrb_sym sym) struct mrb_insn_data data = mrb_last_insn(s); if (!no_peephole(s) && data.insn == OP_MOVE && data.a == dst) { dst = data.b; - s->pc = s->lastpc; + rewind_pc(s); } genop_2(s, op, dst, idx); } @@ -892,7 +997,7 @@ gen_uniop(codegen_scope *s, mrb_sym sym, uint16_t dst) mrb_int n; if (get_int_operand(s, &data, &n)) { - s->pc = s->lastpc; + rewind_pc(s); if (sym == MRB_OPSYM_2(s->mrb, minus)) { n = -n; } @@ -3481,56 +3586,3 @@ mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep) mrb_irep_remove_lv(mrb, (mrb_irep*)irep->reps[i]); } } - -#undef OPCODE -#define Z 1 -#define S 3 -#define W 4 -#define OPCODE(_,x) x, -/* instruction sizes */ -uint8_t mrb_insn_size[] = { -#define B 2 -#define BB 3 -#define BBB 4 -#define BS 4 -#define BSS 6 -#include "mruby/ops.h" -#undef B -#undef BB -#undef BBB -#undef BS -#undef BSS -}; -/* EXT1 instruction sizes */ -uint8_t mrb_insn_size1[] = { -#define B 3 -#define BB 4 -#define BBB 5 -#define BS 5 -#define BSS 7 -#include "mruby/ops.h" -#undef B -#undef BS -#undef BSS -}; -/* EXT2 instruction sizes */ -uint8_t mrb_insn_size2[] = { -#define B 2 -#define BS 4 -#define BSS 6 -#include "mruby/ops.h" -#undef B -#undef BB -#undef BBB -#undef BS -#undef BSS -}; -/* EXT3 instruction sizes */ -#define B 3 -#define BB 5 -#define BBB 6 -#define BS 5 -#define BSS 7 -uint8_t mrb_insn_size3[] = { -#include "mruby/ops.h" -}; |
