mruby-compiler: optimize JMPNOT+JMP to JMPIF in pattern matching

For patterns with a single failure check (like `1 => String`), invert
JMPNOT to JMPIF and eliminate the following JMP instruction.

Before: JMPNOT fail; JMP end; fail: error; end: (8 bytes for jumps)
After:  JMPIF end; error; end: (4 bytes for jump)

The optimization only applies when:
1. There's exactly one JMPNOT in the failure chain
2. The JMPNOT is immediately before the JMP (no code between)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-12-23 20:12:28 +09:00
parent 3af15e0012
commit 2b72d8a7c1
+15 -2
View File
@@ -6402,10 +6402,23 @@ codegen(codegen_scope *s, node *tree, int val)
genop_1(s, OP_LOADT, cursp());
push();
}
match_pos = genjmp(s, OP_JMP, JMPLINK_START);
/* Optimize: single JMPNOT can be inverted to JMPIF, eliminating JMP */
/* Conditions: (1) single entry in fail_pos chain, and
* (2) JMPNOT is immediately before current position (no code between) */
if ((int32_t)(fail_pos + 2) + (int16_t)PEEK_S(s->iseq+fail_pos) == 0 &&
fail_pos + 2 == s->pc) {
/* Single failure point - invert JMPNOT to JMPIF */
s->iseq[fail_pos - 2] = OP_JMPIF;
match_pos = fail_pos;
}
else {
/* Multiple failure points - need JMP to skip error handling */
match_pos = genjmp(s, OP_JMP, JMPLINK_START);
dispatch_linked(s, fail_pos);
}
/* Pattern failed */
dispatch_linked(s, fail_pos);
pop(); /* pop the value */
if (mp->raise_on_fail) {
/* expr => pattern: raise NoMatchingPatternError */