Skip to content

Commit 303253e

Browse files
committed
Reuse dest register for first operand in binary ops (Add, Sub, etc.)
Reuse dest register in unary ops (Not, Neg) Reuse dest register in AddImm/SubImm immediate operations Eliminate unused arg_start register in TailCallGlobal
1 parent 955c5d5 commit 303253e

File tree

3 files changed

+28
-33
lines changed

3 files changed

+28
-33
lines changed

manifest.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"rust"
44
"python"
55
"ruby"
6+
"node"
67
"lua"
78
"bash"
89
"rust:cargo"

src/compiler.rs

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -708,25 +708,23 @@ impl Compiler {
708708
// Check if second arg is a small constant integer
709709
if let Some(imm) = args[1].as_int() {
710710
if imm >= i8::MIN as i64 && imm <= i8::MAX as i64 {
711-
let a_reg = self.alloc_reg();
712-
self.compile_expr(&args[0], a_reg, false)?;
711+
// Optimization: compile first arg directly into dest
712+
self.compile_expr(&args[0], dest, false)?;
713713
if op == "+" {
714-
self.emit(Op::AddImm(dest, a_reg, imm as i8));
714+
self.emit(Op::AddImm(dest, dest, imm as i8));
715715
} else {
716-
self.emit(Op::SubImm(dest, a_reg, imm as i8));
716+
self.emit(Op::SubImm(dest, dest, imm as i8));
717717
}
718-
self.free_reg();
719718
return Ok(Some(true));
720719
}
721720
}
722721
// Check if first arg is a small constant integer (for + only, since + is commutative)
723722
if op == "+" {
724723
if let Some(imm) = args[0].as_int() {
725724
if imm >= i8::MIN as i64 && imm <= i8::MAX as i64 {
726-
let b_reg = self.alloc_reg();
727-
self.compile_expr(&args[1], b_reg, false)?;
728-
self.emit(Op::AddImm(dest, b_reg, imm as i8));
729-
self.free_reg();
725+
// Optimization: compile second arg directly into dest
726+
self.compile_expr(&args[1], dest, false)?;
727+
self.emit(Op::AddImm(dest, dest, imm as i8));
730728
return Ok(Some(true));
731729
}
732730
}
@@ -749,17 +747,15 @@ impl Compiler {
749747
};
750748

751749
if let Some(make_op) = make_binary_op {
752-
// Compile both arguments
753-
let a_reg = self.alloc_reg();
754-
self.compile_expr(&args[0], a_reg, false)?;
750+
// Optimization: compile first arg directly into dest to save a register
751+
self.compile_expr(&args[0], dest, false)?;
755752
let b_reg = self.alloc_reg();
756753
self.compile_expr(&args[1], b_reg, false)?;
757754

758-
// Emit the operation
759-
self.emit(make_op(dest, a_reg, b_reg));
755+
// Emit the operation (dest = dest op b_reg)
756+
self.emit(make_op(dest, dest, b_reg));
760757

761-
// Free temp registers
762-
self.free_reg();
758+
// Free temp register
763759
self.free_reg();
764760

765761
return Ok(Some(true));
@@ -769,19 +765,17 @@ impl Compiler {
769765
// Unary operators
770766
if args.len() == 1 {
771767
if op == "not" {
772-
let a_reg = self.alloc_reg();
773-
self.compile_expr(&args[0], a_reg, false)?;
774-
self.emit(Op::Not(dest, a_reg));
775-
self.free_reg();
768+
// Optimization: compile arg directly into dest
769+
self.compile_expr(&args[0], dest, false)?;
770+
self.emit(Op::Not(dest, dest));
776771
return Ok(Some(true));
777772
}
778773

779774
// Unary minus: (- x)
780775
if op == "-" {
781-
let a_reg = self.alloc_reg();
782-
self.compile_expr(&args[0], a_reg, false)?;
783-
self.emit(Op::Neg(dest, a_reg));
784-
self.free_reg();
776+
// Optimization: compile arg directly into dest
777+
self.compile_expr(&args[0], dest, false)?;
778+
self.emit(Op::Neg(dest, dest));
785779
return Ok(Some(true));
786780
}
787781
}
@@ -824,18 +818,18 @@ impl Compiler {
824818
let nargs = args.len() as u8;
825819

826820
if tail_pos {
827-
// For TailCallGlobal, we need to be careful not to overwrite parameters
828-
// that might be used in later arguments. Compile to temp registers first,
821+
// For TailCallGlobal, compile args to temp registers first,
829822
// then we'll copy to r0, r1, ... at call time.
830-
let arg_start = self.alloc_reg();
823+
// Optimization: track first_arg position without allocating unused marker register
824+
let first_arg = self.locals.len() as Reg;
831825
for arg in args.iter() {
832826
let arg_reg = self.alloc_reg();
833827
self.compile_expr(arg, arg_reg, false)?;
834828
}
835-
self.emit(Op::TailCallGlobal(name_idx, arg_start, nargs));
829+
self.emit(Op::TailCallGlobal(name_idx, first_arg, nargs));
836830
self.emit(Op::LoadNil(dest));
837831
// Free the temp registers
838-
for _ in 0..=nargs {
832+
for _ in 0..nargs {
839833
self.free_reg();
840834
}
841835
} else {

src/vm.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ impl VM {
361361
}
362362
}
363363

364-
Op::TailCallGlobal(name_idx, arg_start, nargs) => {
364+
Op::TailCallGlobal(name_idx, first_arg, nargs) => {
365365
// Optimized: look up global and tail-call directly
366366
let chunk = &self.frames.last().unwrap().chunk;
367367
let symbol_rc = chunk.constants[name_idx as usize].as_symbol_rc()
@@ -394,15 +394,15 @@ impl VM {
394394
// Same function (self-recursion) - no clone needed, just reset IP
395395
frame.ip = 0;
396396
}
397-
// Copy args from temp registers (at arg_start+1, arg_start+2, ...) to base+0, base+1, ...
398-
let src_start = base + arg_start as usize + 1;
397+
// Copy args from temp registers (at first_arg, first_arg+1, ...) to base+0, base+1, ...
398+
let src_start = base + first_arg as usize;
399399
for i in 0..nargs as usize {
400400
self.registers[base + i] = self.registers[src_start + i].clone();
401401
}
402402
} else if let Some(nf) = func_value.as_native_function() {
403403
let func_ptr = nf.func;
404404
let return_reg = self.frames.last().unwrap().return_reg;
405-
let src_start = base + arg_start as usize + 1;
405+
let src_start = base + first_arg as usize;
406406
let src_end = src_start + nargs as usize;
407407
let result = func_ptr(&self.registers[src_start..src_end])?;
408408
self.frames.pop();

0 commit comments

Comments
 (0)