From 6687bddba316b5a63b02847a9511ea8ad86ceea1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Dec 2024 09:26:30 +0900 Subject: [PATCH] mruby-compiler (gen_addsub): merge 2 literal strings str + str Unlike previous attempt, this change can merge sequence of plus operations (e.g. `str + str + str`). Need more tests though. --- mrbgems/mruby-compiler/core/codegen.c | 129 +++++++++++++++++++------- 1 file changed, 98 insertions(+), 31 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 8c4878966..4dcc9810a 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -797,6 +797,97 @@ get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *n) } } +static int new_lit_str2(codegen_scope *s, const char *str1, mrb_int len1, const char *str2, mrb_int len2); + +static void +realloc_pool_str(codegen_scope *s, mrb_irep_pool *p, mrb_int len) +{ + char *str; + if ((p->tt & 3) == IREP_TT_SSTR) { + str = codegen_realloc(s, NULL, len+1); + } + else { + str = (char*)p->u.str; + str = codegen_realloc(s, str, len+1); + } + p->tt = len<<2 | IREP_TT_STR; + str[len] = '\0'; + p->u.str = (const char*)str; +} + +static void +free_pool_str(codegen_scope *s, mrb_irep_pool *p) +{ + if ((p->tt & 3) != IREP_TT_SSTR) { + codegen_realloc(s, (char*)p->u.str, 0); + } + p->u.str = NULL; + s->irep->plen--; +} + +static void +merge_op_string(codegen_scope *s, uint16_t dst, uint16_t b1, uint16_t b2, const mrb_code *pc) +{ + int used = 0; + const mrb_code *i = s->iseq; + + /* scan OP_STRING that refers b1 or b2 */ + mrb_assert(pc < s->iseq + s->icapa); + while (ipool[b1]; + mrb_irep_pool *p2 = &s->pool[b2]; + mrb_int len1 = p1->tt>>2; + mrb_int len2 = p2->tt>>2; + int off; + + switch (used) { + case 0: /* both pools are free */ + case 2: /* b2 is referenced */ + /* overwrite p1; free b2 if possible */ + off = b1; + realloc_pool_str(s, p1, len1+len2); + memcpy((void*)p1->u.str+len1, (void*)p2->u.str, len2); + if (used == 0 && b2+1 == s->irep->plen) { + free_pool_str(s, p2); + } + break; + case 1: /* b1 is referenced */ + /* overwrite p2 */ + off = b2; + realloc_pool_str(s, p2, len1+len2); + memmove((void*)p2->u.str+len1, (void*)p2->u.str, len2); + memcpy((void*)p2->u.str, p1->u.str, len1); + break; + case 3: /* both b1&b2 are referenced */ + /* create new pool */ + off = new_lit_str2(s, p1->u.str, len1, p2->u.str, len2); + break; + } + s->pc = addr_pc(s, pc); + genop_2(s, OP_STRING, dst, off); +} + static void gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) { @@ -811,6 +902,13 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) if (!get_int_operand(s, &data, &n)) { /* not integer immediate */ + if (op == OP_ADD && data.insn == OP_STRING) { + struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); + if (data0.insn == OP_STRING) { + merge_op_string(s, dst, data0.b, data.b, data0.addr); + return; + } + } goto normal; } struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); @@ -2269,26 +2367,6 @@ gen_blkmove(codegen_scope *s, uint16_t ainfo, int lv) push(); } -static int -opt_str_add(codegen_scope *s, node *tree) -{ - /* optimize */ - if (no_optimize(s)) return 0; - /* receiver is a string */ - if (!tree->car || nint(tree->car->car) != NODE_STR) return 0; - /* + call */ - if (!tree->cdr || nsym(tree->cdr->car) != MRB_OPSYM_2(s->mrb, add)) return 0; - /* valid arguments */ - if (!tree->cdr->cdr || tree->cdr->cdr->cdr) return FALSE; - /* takes 1 argument */ - if (!tree->cdr->cdr->car->car && tree->cdr->cdr->car->car->cdr) return 0; - /* valid 1st arguments */ - if (!tree->cdr->cdr->car->car->car) return 0; - if (nint(tree->cdr->cdr->car->car->car->car) == NODE_STR) return 1; - // if (nint(tree->cdr->cdr->car->car->car->car) == NODE_CALL) return 2; - return 0; -} - static void codegen(codegen_scope *s, node *tree, int val) { @@ -2701,17 +2779,6 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_CALL: - if (opt_str_add(s, tree)) { - if (val) { - node *n1 = tree->car->cdr; - node *n2 = tree->cdr->cdr->car->car->car->cdr; - int off = new_lit_str2(s, (char*)n1->car, nint(n1->cdr), (char*)n2->car, nint(n2->cdr)); - genop_2(s, OP_STRING, cursp(), off); - push(); - } - break; - } - /* fall through */ case NODE_FCALL: gen_call(s, tree, val, 0); break;