match now uses new jump; micro-optimize pop_n

This commit is contained in:
Scott Richmond 2025-06-18 15:24:30 -04:00
parent 77f1627132
commit 23298c8538
2 changed files with 49 additions and 53 deletions

View File

@ -410,7 +410,7 @@ impl<'a> Compiler<'a> {
self.chunk.bytecode.push(low); self.chunk.bytecode.push(low);
} }
fn jump_stub(&mut self, op: Op) -> usize { fn stub_jump(&mut self, op: Op) -> usize {
let out = self.chunk.bytecode.len(); let out = self.chunk.bytecode.len();
self.emit_op(op); self.emit_op(op);
self.emit_byte(0xff); self.emit_byte(0xff);
@ -554,9 +554,15 @@ impl<'a> Compiler<'a> {
} }
fn pop_n(&mut self, n: usize) { fn pop_n(&mut self, n: usize) {
self.emit_op(Op::PopN); match n {
self.emit_byte(n); 0 => (),
self.stack_depth -= n; 1 => self.pop(),
n => {
self.emit_op(Op::PopN);
self.emit_byte(n);
self.stack_depth -= n;
}
}
} }
fn enter_loop(&mut self) { fn enter_loop(&mut self) {
@ -657,10 +663,10 @@ impl<'a> Compiler<'a> {
} }
If(cond, then, r#else) => { If(cond, then, r#else) => {
self.visit(cond); self.visit(cond);
let jif_idx = self.jump_stub(Op::JumpIfFalse); let jif_idx = self.stub_jump(Op::JumpIfFalse);
self.stack_depth -= 1; self.stack_depth -= 1;
self.visit(then); self.visit(then);
let jump_idx = self.jump_stub(Op::Jump); let jump_idx = self.stub_jump(Op::Jump);
self.visit(r#else); self.visit(r#else);
self.stack_depth -= 1; self.stack_depth -= 1;
let end_idx = self.len(); let end_idx = self.len();
@ -722,7 +728,7 @@ impl<'a> Compiler<'a> {
self.emit_op(Op::MatchTuple); self.emit_op(Op::MatchTuple);
self.emit_byte(members.len()); self.emit_byte(members.len());
// skip everything if tuple lengths don't match // skip everything if tuple lengths don't match
let before_load_tup_idx = self.jump_stub(Op::JumpIfNoMatch); let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch);
// set up the per-member conditional logic // set up the per-member conditional logic
let mut jump_idxes = vec![]; let mut jump_idxes = vec![];
@ -743,11 +749,11 @@ impl<'a> Compiler<'a> {
// visit the pattern member // visit the pattern member
self.visit(member); self.visit(member);
// and jump if there's no match // and jump if there's no match
jump_idxes.push(self.jump_stub(Op::JumpIfNoMatch)); jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch));
} }
// if we get here--not having jumped on no match--we're matched; jump the "no match" code // if we get here--not having jumped on no match--we're matched; jump the "no match" code
let jump_idx = self.jump_stub(Op::Jump); let jump_idx = self.stub_jump(Op::Jump);
// patch up the previous no match jumps to jump to clean-up code // patch up the previous no match jumps to jump to clean-up code
for idx in jump_idxes { for idx in jump_idxes {
@ -774,7 +780,7 @@ impl<'a> Compiler<'a> {
ListPattern(members) => { ListPattern(members) => {
self.emit_op(Op::MatchList); self.emit_op(Op::MatchList);
self.emit_byte(members.len()); self.emit_byte(members.len());
let before_load_tup_idx = self.jump_stub(Op::JumpIfNoMatch); let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch);
let mut jump_idxes = vec![]; let mut jump_idxes = vec![];
let match_depth = self.match_depth; let match_depth = self.match_depth;
@ -788,10 +794,10 @@ impl<'a> Compiler<'a> {
self.emit_op(Op::MatchDepth); self.emit_op(Op::MatchDepth);
self.emit_byte(self.match_depth); self.emit_byte(self.match_depth);
self.visit(member); self.visit(member);
jump_idxes.push(self.jump_stub(Op::JumpIfNoMatch)); jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch));
} }
let jump_idx = self.jump_stub(Op::Jump); let jump_idx = self.stub_jump(Op::Jump);
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx - 2) self.patch_jump(idx, self.len() - idx - 2)
@ -809,7 +815,7 @@ impl<'a> Compiler<'a> {
DictPattern(pairs) => { DictPattern(pairs) => {
self.emit_op(Op::MatchDict); self.emit_op(Op::MatchDict);
self.emit_byte(pairs.len()); self.emit_byte(pairs.len());
let before_load_dict_idx = self.jump_stub(Op::JumpIfNoMatch); let before_load_dict_idx = self.stub_jump(Op::JumpIfNoMatch);
let mut jump_idxes = vec![]; let mut jump_idxes = vec![];
let dict_stack_pos = self.stack_depth - 1; let dict_stack_pos = self.stack_depth - 1;
@ -821,9 +827,9 @@ impl<'a> Compiler<'a> {
self.emit_op(Op::LoadDictValue); self.emit_op(Op::LoadDictValue);
self.emit_byte(dict_stack_pos); self.emit_byte(dict_stack_pos);
self.visit(pattern); self.visit(pattern);
jump_idxes.push(self.jump_stub(Op::JumpIfNoMatch)); jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch));
} }
let jump_idx = self.jump_stub(Op::Jump); let jump_idx = self.stub_jump(Op::Jump);
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx - 2); self.patch_jump(idx, self.len() - idx - 2);
@ -867,9 +873,7 @@ impl<'a> Compiler<'a> {
self.emit_op(Op::MatchString); self.emit_op(Op::MatchString);
self.emit_byte(pattern_idx); self.emit_byte(pattern_idx);
self.emit_op(Op::JumpIfNoMatch); let jnm_idx = self.stub_jump(Op::JumpIfNoMatch);
let jnm_idx = self.len();
self.emit_byte(0xff);
self.emit_op(Op::PushStringMatches); self.emit_op(Op::PushStringMatches);
self.emit_byte(pattern_idx); self.emit_byte(pattern_idx);
@ -885,7 +889,7 @@ impl<'a> Compiler<'a> {
self.stack_depth += 1; self.stack_depth += 1;
} }
self.chunk.bytecode[jnm_idx] = (self.len() - jnm_idx - 1) as u8; self.patch_jump(jnm_idx, self.len() - jnm_idx - 3);
} }
PairPattern(_, _) => unreachable!(), PairPattern(_, _) => unreachable!(),
Tuple(members) => { Tuple(members) => {
@ -953,12 +957,10 @@ impl<'a> Compiler<'a> {
for arg in args { for arg in args {
self.visit(arg); self.visit(arg);
self.emit_op(Op::Stash); self.emit_op(Op::Stash);
self.emit_op(Op::JumpIfTrue); jump_idxes.push(self.stub_jump(Op::JumpIfTrue));
jump_idxes.push(self.len());
self.emit_byte(0xff);
} }
for idx in jump_idxes { for idx in jump_idxes {
self.chunk.bytecode[idx] = (self.len() - idx + 2) as u8; self.patch_jump(idx, self.len() - idx);
} }
self.emit_op(Op::Load); self.emit_op(Op::Load);
} else { } else {
@ -973,12 +975,10 @@ impl<'a> Compiler<'a> {
for arg in args { for arg in args {
self.visit(arg); self.visit(arg);
self.emit_op(Op::Stash); self.emit_op(Op::Stash);
self.emit_op(Op::JumpIfFalse); jump_idxes.push(self.stub_jump(Op::JumpIfFalse));
jump_idxes.push(self.len());
self.emit_byte(0xff);
} }
for idx in jump_idxes { for idx in jump_idxes {
self.chunk.bytecode[idx] = (self.len() - idx + 2) as u8; self.patch_jump(idx, self.len() - idx);
} }
self.emit_op(Op::Load); self.emit_op(Op::Load);
} else { } else {
@ -1048,20 +1048,16 @@ impl<'a> Compiler<'a> {
let mut clauses = clauses.iter(); let mut clauses = clauses.iter();
while let Some((WhenClause(cond, body), _)) = clauses.next() { while let Some((WhenClause(cond, body), _)) = clauses.next() {
self.visit(cond.as_ref()); self.visit(cond.as_ref());
self.emit_op(Op::JumpIfFalse); let jif_jump_idx = self.stub_jump(Op::JumpIfFalse);
let jif_jump_idx = self.len();
self.emit_byte(0xff);
self.stack_depth -= 1; self.stack_depth -= 1;
self.visit(body); self.visit(body);
self.stack_depth -= 1; self.stack_depth -= 1;
self.emit_op(Op::Jump); jump_idxes.push(self.stub_jump(Op::Jump));
jump_idxes.push(self.len()); self.patch_jump(jif_jump_idx, self.len() - jif_jump_idx - 3);
self.emit_byte(0xff);
self.chunk.bytecode[jif_jump_idx] = (self.len() - jif_jump_idx) as u8 - 1;
} }
self.emit_op(Op::PanicNoWhen); self.emit_op(Op::PanicNoWhen);
for idx in jump_idxes { for idx in jump_idxes {
self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1; self.patch_jump(idx, self.len() - idx - 3);
} }
self.stack_depth += 1; self.stack_depth += 1;
} }
@ -1076,16 +1072,12 @@ impl<'a> Compiler<'a> {
self.scope_depth += 1; self.scope_depth += 1;
self.match_depth = 0; self.match_depth = 0;
self.visit(pattern); self.visit(pattern);
self.emit_op(Op::JumpIfNoMatch); no_match_jumps.push(self.stub_jump(Op::JumpIfNoMatch));
no_match_jumps.push(self.len());
self.emit_byte(0xff);
if guard.is_some() { if guard.is_some() {
let guard_expr: &'static Spanned<Ast> = let guard_expr: &'static Spanned<Ast> =
Box::leak(Box::new(guard.clone().unwrap())); Box::leak(Box::new(guard.clone().unwrap()));
self.visit(guard_expr); self.visit(guard_expr);
self.emit_op(Op::JumpIfFalse); no_match_jumps.push(self.stub_jump(Op::JumpIfFalse));
no_match_jumps.push(self.len());
self.emit_byte(0xff);
self.stack_depth -= 1; self.stack_depth -= 1;
} }
self.visit(body); self.visit(body);
@ -1098,23 +1090,22 @@ impl<'a> Compiler<'a> {
break; break;
} }
} }
while self.stack_depth > stack_depth { self.pop_n(self.stack_depth - stack_depth);
self.pop(); jump_idxes.push(self.stub_jump(Op::Jump));
}
self.emit_op(Op::Jump);
jump_idxes.push(self.len());
self.emit_byte(0xff);
for idx in no_match_jumps { for idx in no_match_jumps {
self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1; self.patch_jump(idx, self.len() - idx - 3);
} }
} }
self.emit_op(Op::PanicNoMatch); self.emit_op(Op::PanicNoMatch);
for idx in jump_idxes { for idx in jump_idxes {
self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1; self.patch_jump(idx, self.len() - idx - 3);
} // self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
while self.stack_depth > stack_depth {
self.pop();
} }
self.pop_n(self.stack_depth - stack_depth);
// while self.stack_depth > stack_depth {
// self.pop();
// }
self.emit_op(Op::Load); self.emit_op(Op::Load);
self.stack_depth += 1; self.stack_depth += 1;
} }

View File

@ -75,7 +75,12 @@ pub fn run(src: &'static str) {
pub fn main() { pub fn main() {
// env::set_var("RUST_BACKTRACE", "1"); // env::set_var("RUST_BACKTRACE", "1");
let src = " let src = "
let #{:a 1, :b (2, #{:c 3})} = #{:a 1, :b (1, #{:c 3})} match :foo with {
:foo if false -> :bar
:bar -> :baz
:foo if true -> :quux
:thing -> :oops
}
"; ";
run(src); run(src);
} }