add recursion, add benchmarks

This commit is contained in:
zongor 2025-07-12 23:14:23 -04:00
parent 19a69d3be5
commit 7598a93b31
13 changed files with 152 additions and 27 deletions

View File

@ -30,7 +30,7 @@ int main(int argc, char **argv) {
vm.return_stack_size = STACK_SIZE;
vm.stack_size = STACK_SIZE;
vm.memory_size = MEMORY_SIZE;
test_add_function_compile(vm.memory);
test_recursive_function_compile(vm.memory);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(mainloop, 0, 1);

View File

@ -23,7 +23,7 @@ typedef struct {
} Frame;
#define MEMORY_SIZE 65536
#define FRAMES_SIZE 32
#define FRAMES_SIZE 128
#define STACK_SIZE 256
typedef struct {
uint32_t pc; /* Program counter */

View File

@ -67,32 +67,42 @@ uint32_t test_add_function_compile(Value *memory) {
}
uint32_t test_recursive_function_compile(Value *memory) {
uint32_t i = 3;
memory[i++].u = OP(OP_POPU, 0, 0, 0); /* return ptr */
memory[i++].u = OP(OP_POPI, 1, 0, 0); /* n int */
/* if (n < 2) */
/* return n; */
memory[i++].u = OP(OP_POPI, 2, 0, 0); /* fib(n - 2) */
memory[i++].u = OP(OP_POPI, 3, 0, 0); /* fib(n - 1) */
memory[i++].u = OP(OP_ADD_INT, 4, 3, 2); /* add */
memory[i++].u = OP(OP_PUSHI, 4, 0, 0); /* return */
memory[i++].u = OP(OP_RETURN, 0, 0, 0);
uint32_t main = i;
memory[0].u = OP(OP_LOADF, 0, 0, 0);
memory[1].u = main;
memory[2].u = OP(OP_JMP, 0, 0, 0); /* jump to 'main' */
uint32_t i = 0;
/* fn main() */
memory[i++].u = OP(OP_LOADI, 0, 0, 0); /* 35 */
memory[i++].i = 35;
memory[i++].u = OP(OP_PUSHI, 0, 0, 0);
uint32_t add_fn_return = i + 6; /* after the call */
memory[i++].u = OP(OP_LOADI, 0, 0, 0); /* return */
memory[i++].u = add_fn_return;
memory[i++].u = OP(OP_PUSHU, 0, 0, 0);
memory[i++].u = OP(OP_LOADU, 0, 0, 0); /* add fn ptr */
memory[i++].u = 3;
memory[i++].u = OP(OP_CALL, 0, 0, 0); /* ); */
memory[i++].u = 9;
memory[i++].u = OP(OP_POPI, 0, 0, 0); /* get return value */
memory[i++].u = OP(OP_INT_TO_STRING, 1, 0, 0);
memory[i++].u = OP(OP_PRINT_STRING, 0, 1, 0); /* print(fib(35).toS()); */
memory[i++].u = OP(OP_HALT, 0, 0, 0);
/* fn fib() */
memory[i++].u = OP(OP_POPI, 0, 0, 0); /* n int */
memory[i++].u = OP(OP_LOADI, 1, 0, 0); /* 2 */
memory[i++].i = 2;
memory[i++].u = OP(OP_LOADI, 2, 0, 0); /* &fib */
memory[i++].i = 32;
memory[i++].u = OP(OP_JLT_INT, 2, 0, 1);
memory[i++].u = OP(OP_LOADI, 3, 0, 0); /* 2 */
memory[i++].i = 2;
memory[i++].u = OP(OP_SUB_INT, 4, 0, 3);
memory[i++].u = OP(OP_PUSHI, 4, 0, 0);
memory[i++].u = OP(OP_CALL, 0, 0, 0); /* fib(n - 2) */
memory[i++].u = 9;
memory[i++].u = OP(OP_LOADI, 3, 0, 0); /* 1 */
memory[i++].i = 1;
memory[i++].u = OP(OP_SUB_INT, 4, 0, 3);
memory[i++].u = OP(OP_PUSHI, 4, 0, 0);
memory[i++].u = OP(OP_CALL, 0, 0, 0); /* fib(n - 1) */
memory[i++].u = 9;
memory[i++].u = OP(OP_POPI, 4, 0, 0);
memory[i++].u = OP(OP_POPI, 5, 0, 0);
memory[i++].u = OP(OP_ADD_INT, 6, 5, 4);
memory[i++].u = OP(OP_PUSHI, 6, 0, 0);
memory[i++].u = OP(OP_RETURN, 0, 0, 0);
memory[i++].u = OP(OP_PUSHI, 0, 0, 0);
memory[i++].u = OP(OP_RETURN, 0, 0, 0);
return i;
}

View File

@ -49,7 +49,23 @@ bool step_vm(VM *vm) {
/* Advance to next instruction */
vm->pc++;
#ifdef DEBUG
printOp(opcode, dest, src1, src2);
printf("dest=%d, src1=%d, src2=%d\n", vm->frames[vm->fp].registers[dest].u,
vm->frames[vm->fp].registers[src1].i,
vm->frames[vm->fp].registers[src2].i);
uint32_t i;
printf("return_stack[");
for (i = 0; i < vm->rp; i++)
printf("%d,", vm->return_stack[i].u);
printf("]\n");
printf("stack[");
for (i = 0; i < vm->sp; i++)
printf("%d,", vm->stack[i].i);
printf("]\n");
#endif
switch (opcode) {
case OP_HALT:
@ -66,9 +82,6 @@ bool step_vm(VM *vm) {
case OP_RETURN:
vm->pc = vm->return_stack[--vm->rp].u; /* set pc to return address */
Slice s = vm->frames[vm->fp].allocated; /* get allocated slice */
memset(&vm->memory[s.start], 0,
s.end - s.start); /* deallocate memory from slice */
memset(&vm->frames[vm->fp], 0, sizeof(Frame)); /* reset the frame */
vm->fp--; /* pop the frame */
vm->mp = s.start; /* reset memory pointer to start of old slice */
return true;

View File

@ -13,4 +13,5 @@ add:
popi $0 ; int a
popi $1 ; int b
addi $2 $1 $0 ; a + b
return $2 ; actually do the return
pushi $2
return ; actually do the return

8
test/bench/fib.lua Normal file
View File

@ -0,0 +1,8 @@
function fib(n)
if n < 2 then return n end
return fib(n-1) + fib(n-2)
end
local result = fib(35)
print(result)

12
test/bench/fib.pl Normal file
View File

@ -0,0 +1,12 @@
use strict;
use warnings;
sub fib {
my $n = shift;
return $n if $n < 2;
return fib($n-1) + fib($n-2);
}
my $result = fib(35);
print "$result\n";

7
test/bench/fib.py Normal file
View File

@ -0,0 +1,7 @@
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
result = fib(35)
print(result)

10
test/bench/fib.wren Normal file
View File

@ -0,0 +1,10 @@
class Fib {
static fib(n) {
if (n < 2) return n
return fib(n-1) + fib(n-2)
}
}
var result = Fib.fib(35)
System.print(result)

6
test/bench/fib.zre Normal file
View File

@ -0,0 +1,6 @@
fn fib(n) {
if (n < 2) return n;
return fib(n - 2) + fib(n - 1);
}
print fib(35);

29
test/bench/run.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
# Exit on error
set -e
# Function to print section headers
print_section() {
printf '\n\e[1;34m%s\e[0m\n' "$1"
}
# Lua Implementation
print_section "Lua (fib.lua)"
time lua fib.lua
# Perl Implementation
print_section "Perl (fib.pl)"
time perl fib.pl
# Python Implementation
print_section "Python (fib.py)"
time python3 fib.py
# Wren Implementation
print_section "Wren (fib.wren)"
time wren fib.wren
# ZRE Implementation
print_section "zre (fib.zre)"
time ../../src/zre #currently hardcoded

29
test/fib.s Normal file
View File

@ -0,0 +1,29 @@
main:
loadi $0 23
pushi $0
call &fib
popi $0
itos $1 $0
puts $1
halt
fib:
popi $0
loadi $1 2
loadi $2 &base_case
jlt $2 $0 $1
loadi $2 2
subi $4 $0 $3
pushi $4
call &fib
load $2 1
subi $4 $0 $3
pushi $4
call &fib
popi $4
popi $5
addi $6 $5 $4
pushi $6
return
base_case:
pushi $0
return

View File

@ -1,4 +1,4 @@
int fib(int n) {
fn fib(n int) {
if (n < 2) {
return n;
}