mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
vm: add OP_GETIDX0 for fast array[0] access
Fuses MOVE+LOADI_0+GETIDX pattern into single instruction. Saves 4 bytes per arr[0] access (7 bytes -> 3 bytes). Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -48,6 +48,7 @@ OPCODE(SETMCNST, BB) /* R[a+1]::Syms[b] = R[a] */
|
||||
OPCODE(GETUPVAR, BBB) /* R[a] = uvget(b,c) */
|
||||
OPCODE(SETUPVAR, BBB) /* uvset(b,c,R[a]) */
|
||||
OPCODE(GETIDX, B) /* R[a] = R[a][R[a+1]] */
|
||||
OPCODE(GETIDX0, BB) /* R[a] = R[b][0]; a+1 for method call */
|
||||
OPCODE(SETIDX, B) /* R[a][R[a+1]] = R[a+2] */
|
||||
OPCODE(JMP, S) /* pc+=a */
|
||||
OPCODE(JMPIF, BS) /* if R[a] pc+=b */
|
||||
|
||||
@@ -1554,6 +1554,16 @@ gen_binop(codegen_scope *s, mrb_sym op, uint16_t dst)
|
||||
{
|
||||
if (no_peephole(s)) return FALSE;
|
||||
else if (op == MRB_OPSYM_2(s->mrb, aref)) {
|
||||
/* GETIDX0 fusion: MOVE dst arr; LOADI_0 dst+1 -> GETIDX0 dst arr */
|
||||
struct mrb_insn_data data = mrb_last_insn(s);
|
||||
if (data.insn == OP_LOADI_0 && data.a == dst+1 && addr_pc(s, data.addr) != s->lastlabel) {
|
||||
struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr));
|
||||
if (data0.insn == OP_MOVE && data0.a == dst && data0.b != dst) {
|
||||
s->pc = addr_pc(s, data0.addr);
|
||||
genop_2(s, OP_GETIDX0, dst, data0.b);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
genop_1(s, OP_GETIDX, dst);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -303,6 +303,9 @@ codedump(mrb_state *mrb, const mrb_irep *irep, FILE *out)
|
||||
CASE(OP_GETIDX, B):
|
||||
fprintf(out, "GETIDX\tR%d\t(R%d)\n", a, a+1);
|
||||
break;
|
||||
CASE(OP_GETIDX0, BB):
|
||||
fprintf(out, "GETIDX0\tR%d\tR%d[0]\n", a, b);
|
||||
break;
|
||||
CASE(OP_SETIDX, B):
|
||||
fprintf(out, "SETIDX\tR%d\t(R%d)\t(R%d)\n", a, a+1, a+2);
|
||||
break;
|
||||
|
||||
@@ -1938,6 +1938,33 @@ RETRY_TRY_BLOCK:
|
||||
goto L_SEND_SYM;
|
||||
}
|
||||
|
||||
CASE(OP_GETIDX0, BB) {
|
||||
mrb_value recv = regs[b];
|
||||
enum mrb_vtype tt = mrb_type(recv);
|
||||
|
||||
if (mrb_likely(tt == MRB_TT_ARRAY)) {
|
||||
struct RArray *ary = mrb_ary_ptr(recv);
|
||||
if (mrb_unlikely(ary->c != mrb->array_class)) goto getidx0_fallback;
|
||||
if (ARY_EMBED_P(ary)) {
|
||||
regs[a] = ARY_EMBED_LEN(ary) > 0 ? ary->as.ary[0] : mrb_nil_value();
|
||||
}
|
||||
else {
|
||||
regs[a] = ary->as.heap.len > 0 ? ary->as.heap.ptr[0] : mrb_nil_value();
|
||||
}
|
||||
NEXT;
|
||||
}
|
||||
else if (tt == MRB_TT_HASH) {
|
||||
if (mrb_obj_ptr(recv)->c != mrb->hash_class) goto getidx0_fallback;
|
||||
regs[a] = mrb_hash_get(mrb, recv, mrb_fixnum_value(0));
|
||||
NEXT;
|
||||
}
|
||||
getidx0_fallback:
|
||||
regs[a] = recv;
|
||||
SET_FIXNUM_VALUE(regs[a+1], 0);
|
||||
mid = MRB_OPSYM(aref);
|
||||
goto L_SEND_SYM;
|
||||
}
|
||||
|
||||
CASE(OP_SETIDX, B) {
|
||||
mrb_value va = regs[a], vb = regs[a+1], vc = regs[a+2];
|
||||
switch (mrb_type(va)) {
|
||||
|
||||
Reference in New Issue
Block a user