diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 9602dc51b..4fe79d115 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -78,6 +78,8 @@ OPCODE(ADD, B) /* R[a] = R[a]+R[a+1] */ OPCODE(ADDI, BB) /* R[a] = R[a]+mrb_int(b) */ OPCODE(SUB, B) /* R[a] = R[a]-R[a+1] */ OPCODE(SUBI, BB) /* R[a] = R[a]-mrb_int(b) */ +OPCODE(ADDILV, BBB) /* R[a] = R[a]+mrb_int(c); R[b],R[b+1] for method call */ +OPCODE(SUBILV, BBB) /* R[a] = R[a]-mrb_int(c); R[b],R[b+1] for method call */ OPCODE(MUL, B) /* R[a] = R[a]*R[a+1] */ OPCODE(DIV, B) /* R[a] = R[a]/R[a+1] */ OPCODE(EQ, B) /* R[a] = R[a]==R[a+1] */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 9a0c2d257..1c1382519 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -996,17 +996,22 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) if (data0.insn != OP_MOVE || data0.a != data.a || data0.b != dst) break; if (addr_pc(s, data0.addr) != s->lastlabel) { /* constant folding */ - data0 = mrb_decode_insn(mrb_prev_pc(s, data0.addr)); + struct mrb_insn_data data1 = mrb_decode_insn(mrb_prev_pc(s, data0.addr)); mrb_int n; - if (data0.a == dst && get_int_operand(s, &data0, &n)) { + if (data1.a == dst && get_int_operand(s, &data1, &n)) { if ((data.insn == OP_ADDI && !mrb_int_add_overflow(n, data.b, &n)) || (data.insn == OP_SUBI && !mrb_int_sub_overflow(n, data.b, &n))) { - s->pc = addr_pc(s, data0.addr); + s->pc = addr_pc(s, data1.addr); gen_int(s, dst, n); return; } } } + /* ADDILV/SUBILV fusion: MOVE temp local; ADDI temp imm; MOVE local temp */ + /* -> ADDILV local temp imm (temp is working space for method fallback) */ + s->pc = addr_pc(s, data0.addr); + genop_3(s, data.insn == OP_ADDI ? OP_ADDILV : OP_SUBILV, dst, data.a, data.b); + return; } break; default: diff --git a/src/codedump.c b/src/codedump.c index 58962c83d..02fc59f4d 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -444,6 +444,14 @@ codedump(mrb_state *mrb, const mrb_irep *irep, FILE *out) fprintf(out, "SUBI\t\tR%d\t%d", a, b); print_lv_a(mrb, irep, a, out); break; + CASE(OP_ADDILV, BBB): + fprintf(out, "ADDILV\tR%d\tR%d\t%d", a, b, c); + print_lv_a(mrb, irep, a, out); + break; + CASE(OP_SUBILV, BBB): + fprintf(out, "SUBILV\tR%d\tR%d\t%d", a, b, c); + print_lv_a(mrb, irep, a, out); + break; CASE(OP_MUL, B): fprintf(out, "MUL\t\tR%d\t(R%d)\n", a, a+1); break; diff --git a/src/vm.c b/src/vm.c index 5568ff54b..3b76d18ab 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2937,6 +2937,51 @@ RETRY_TRY_BLOCK: OP_MATHI(sub); } +#ifdef MRB_NO_FLOAT +#define OP_MATHILV_CASE_FLOAT(op_name) (void)0 +#else +#define OP_MATHILV_CASE_FLOAT(op_name) \ + case MRB_TT_FLOAT: \ + { \ + mrb_float z = mrb_float(regs[a]) OP_MATH_OP_##op_name c; \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break +#endif +#define OP_MATHILV(op_name) \ + /* a=local, b=working space, c=immediate */ \ + switch (mrb_type(regs[a])) { \ + case MRB_TT_INTEGER: \ + { \ + mrb_int x = mrb_integer(regs[a]), y = (mrb_int)c, z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) { \ + OP_MATH_OVERFLOW_INT(op_name,x,y); \ + } \ + else { \ + SET_INT_VALUE(mrb,regs[a], z); \ + } \ + } \ + break; \ + OP_MATHILV_CASE_FLOAT(op_name); \ + default: \ + { \ + mrb_value arg = mrb_int_value(mrb, c); \ + mrb_sym mid = MRB_OPSYM(op_name); \ + regs[a] = mrb_funcall_argv(mrb, regs[a], mid, 1, &arg); \ + mrb_gc_arena_restore(mrb, ai); \ + } \ + break; \ + } \ + NEXT + + CASE(OP_ADDILV, BBB) { + OP_MATHILV(add); + } + + CASE(OP_SUBILV, BBB) { + OP_MATHILV(sub); + } + #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) #ifdef MRB_NO_FLOAT