benchmarking; changed arg length from 3 to 2

This commit is contained in:
prod2 2022-01-21 18:37:46 +01:00
parent 35d2b96651
commit 8a956debc6
7 changed files with 62 additions and 51 deletions

9
benchmarks/fib.lua Normal file
View File

@ -0,0 +1,9 @@
local function fib(n)
if n < 2 then
return 1
else
return fib(n-1) + fib(n-2)
end
end
print(fib(37))

View File

@ -3,5 +3,4 @@ var fib = funct(n)
else ^result = fib(n-1) + fib(n-2)
;
print fib(25);
print fib(37);

7
benchmarks/fib.py Normal file
View File

@ -0,0 +1,7 @@
def fib(n):
if n < 2:
return 1
else:
return fib(n-1) + fib(n-2)
print(fib(37))

View File

@ -23,7 +23,10 @@ type
lines*: seq[int]
name*: string # name of the module/chunk/files
Triple* = array[3, uint8]
DoubleUint8* = array[2, uint8]
const argSize* = 2
const argMax*: int = 256*256
proc initChunk*(name: string): Chunk =
Chunk(code: @[], name: name, lines: @[], constants: @[])
@ -36,7 +39,7 @@ proc writeChunk*(ch: var Chunk, code: OpCode, line: int) =
ch.code.add(code.uint8)
ch.lines.add(line)
proc writeChunk*(ch: var Chunk, code: Triple, line: int) =
proc writeChunk*(ch: var Chunk, code: DoubleUint8, line: int) =
for c in code:
ch.code.add(c)
ch.lines.add(line)
@ -44,16 +47,11 @@ proc writeChunk*(ch: var Chunk, code: Triple, line: int) =
proc len*(ch: Chunk): int =
ch.code.len
proc toTriple*(integer: int): Triple =
var integer = integer
result[0] = integer.uint8
integer = integer div 256
result[1] = integer.uint8
integer = integer div 256
result[2] = integer.uint8
proc toDU8*(integ: int): DoubleUint8 =
cast[ptr array[2, uint8]](integ.unsafeAddr)[]
proc toInt*(triple: Triple): int =
triple[0].int + triple[1].int * 256 + triple[2].int * 256 * 256
proc toInt*(du8: DoubleUint8): int =
cast[uint16](du8).int
proc addConstant*(ch: var Chunk, constant: KonValue): int =
ch.constants.add(constant)
@ -62,7 +60,7 @@ proc addConstant*(ch: var Chunk, constant: KonValue): int =
proc writeConstant*(ch: var Chunk, constant: KonValue, line: int): int =
result = ch.addConstant(constant)
ch.writeChunk(opConstant, line)
ch.writeChunk(result.toTriple, line)
ch.writeChunk(result.toDU8, line)
const simpleInstructions = {
opReturn,
@ -83,7 +81,6 @@ const argInstructions = {
opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop,
}
const tripleMax*: int = 16777215
proc disassembleChunk*(ch: Chunk) =
echo &"== Chunk {ch.name} begin =="
@ -93,7 +90,7 @@ proc disassembleChunk*(ch: Chunk) =
while c < ch.code.len:
template instruction: uint8 = ch.code[c]
template line: int = ch.lines[c]
template triple: Triple = [ch.code[c+1], ch.code[c+2], ch.code[c+3]]
template double: DoubleUint8 = [ch.code[c+1], ch.code[c+2]]
let cFmt = &"{c:04}"
let lineFmt = if lastLine == line: " | " else: &"{line:04}"
try:
@ -102,13 +99,13 @@ proc disassembleChunk*(ch: Chunk) =
of simpleInstructions:
write stdout, ")\n"
of argInstructions:
write stdout, &" {triple[0].toHex(2)} {triple[1].toHex(2)} {triple[2].toHex(2)})\n"
c += 3
write stdout, &" {double[0].toHex(2)} {double[1].toHex(2)})\n"
c += 2
of constantInstructions:
let i = triple.toInt
write stdout, &" {triple[0].toHex(2)} {triple[1].toHex(2)} {triple[2].toHex(2)})\n"
let i = double.toInt
write stdout, &" {double[0].toHex(2)} {double[1].toHex(2)})\n"
echo &" points to constant {ch.constants[i]} (i: {i})"
c += 3
c += 2
except:
echo &"[{cFmt}] {lineFmt} Unknown opcode {instruction}"
c.inc

View File

@ -131,7 +131,7 @@ proc synchronize(comp: Compiler) =
return
comp.advance()
proc writeChunk(comp: Compiler, dStackIndex: int, ch: OpCode | Triple) =
proc writeChunk(comp: Compiler, dStackIndex: int, ch: OpCode | DoubleUint8) =
comp.stackIndex += dStackIndex
when debugCompiler:
debugEcho &"new stackindex: {comp.stackIndex}, delta: {dStackIndex} due to {ch.repr}"
@ -140,12 +140,12 @@ proc writeChunk(comp: Compiler, dStackIndex: int, ch: OpCode | Triple) =
proc writeConstant(comp: Compiler, constant: KonValue) =
comp.stackIndex.inc
let index = comp.chunk.writeConstant(constant, comp.previous.line)
if index >= tripleMax:
if index >= argMax:
comp.error("Too many constants in one chunk.")
proc addLocal(comp: Compiler, name: string, delta: int) =
if comp.locals.len >= tripleMax:
if comp.locals.len >= argMax:
comp.error("Too many local variables in function.")
# if delta is 0 or negative, it means that it is already on the stack when addLocal is called
@ -194,29 +194,28 @@ proc emitJump(comp: Compiler, delta: int, op: OpCode): int =
# delta -> 0 if the jump does not pop
# delta -> -1 if the jump pops the condition from the stack
comp.writeChunk(delta, op)
comp.writeChunk(0, 0xffffff.toTriple)
comp.chunk.len - 3
comp.writeChunk(0, 0xffffff.toDU8)
comp.chunk.len - argSize
proc patchJump(comp: Compiler, offset: int) =
let jump = (comp.chunk.len - offset - 3)
let jump = (comp.chunk.len - offset - argSize)
if (jump > tripleMax):
if (jump > argMax):
comp.error("Too much code to jump over.")
let jumpt = jump.toTriple
let jumpt = jump.toDU8
comp.chunk.code[offset] = jumpt[0]
comp.chunk.code[offset + 1] = jumpt[1]
comp.chunk.code[offset + 2] = jumpt[2]
proc emitLoop(comp: Compiler, loopstart: int, delta: int, op: OpCode) =
comp.writeChunk(delta, op)
let offset = comp.chunk.len - loopstart + 3
if offset > tripleMax:
let offset = comp.chunk.len - loopstart + argSize
if offset > argMax:
comp.error("Loop body too large.")
comp.writeChunk(0, offset.toTriple)
comp.writeChunk(0, offset.toDU8)
# SCOPE HELPERS
proc beginScope(comp: Compiler, function: bool = false) =
@ -413,7 +412,7 @@ proc variable(comp: Compiler) =
# get (global/local)
comp.writeChunk(1, getOp)
comp.writeChunk(0, arg.toTriple)
comp.writeChunk(0, arg.toDU8)
tkIdentifier.genRule(variable, nop, pcNone)
@ -443,7 +442,7 @@ proc parseCall(comp: Compiler) =
# emit call
comp.writeChunk(-argcount, opCall)
comp.writeChunk(0, argcount.toTriple)
comp.writeChunk(0, argcount.toDU8)
tkLeftParen.genRule(grouping, parseCall, pcCall)
@ -583,7 +582,7 @@ proc parseWhile(comp: Compiler) =
# stack size inside code that is conditional must be 0!
# body
comp.writeChunk(-1, opPop) # pop the old result
comp.writeChunk(-1, opPop) # pop the old return value
comp.expression()
# net stack change: 1 + -1 = 0
@ -706,7 +705,7 @@ proc defineVariable(comp: Compiler, index: int) =
comp.markInitialized()
else:
comp.writeChunk(-1, opDefineGlobal)
comp.writeChunk(0, index.toTriple)
comp.writeChunk(0, index.toDU8)
proc varStatement(comp: Compiler) =
let globalIndex = comp.parseVariable("Expect variable name.")

View File

@ -8,8 +8,8 @@ const debugVM* = false
const debugScanner* = false
const debugCompiler* = false
const debugDumpChunk* = false
const assertionsVM* = true # sanity checks in the VM, such as the stack being empty at the end
const assertionsCompiler* = true # sanity checks in the compiler
const assertionsVM* = false # sanity checks in the VM, such as the stack being empty at the end
const assertionsCompiler* = false # sanity checks in the compiler
# choose a line editor for the repl
const lineEditor = leRdstdin

24
vm.nim
View File

@ -55,11 +55,11 @@ proc advance(vm: VM): uint8 =
vm.line = vm.chunk.lines[vm.ii-1]
vm.chunk.code[vm.ii-1]
proc readTriple(vm: VM): int =
[vm.advance, vm.advance, vm.advance].toInt
proc readDU8(vm: VM): int =
[vm.advance, vm.advance].toInt
proc readConstant(vm: VM): KonValue =
let index = vm.readTriple()
let index = vm.readDU8()
vm.chunk.constants[index]
proc binary(op: OpCode, left: KonValue, right: KonValue): KonValue =
@ -94,7 +94,7 @@ proc run*(vm: VM): InterpretResult =
msg &= &"{e} "
msg &= "]"
echo msg
{.computedgoto.} # See https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
case ins:
of opConstant:
let val: KonValue = vm.readConstant()
@ -103,7 +103,7 @@ proc run*(vm: VM): InterpretResult =
let val = vm.pop.negate
if not vm.pushSafe(val):
break
of {opAdd, opSubtract, opMultiply, opDivide}:
of opAdd, opSubtract, opMultiply, opDivide:
let right = vm.pop()
let left = vm.pop()
if not vm.pushSafe(binary(ins, left, right)):
@ -156,24 +156,24 @@ proc run*(vm: VM): InterpretResult =
of opPop:
discard vm.pop()
of opGetLocal:
let slot = vm.readTriple()
let slot = vm.readDU8()
vm.push(vm.stack[slot + frameBottom])
of opSetLocal:
let slot = vm.readTriple()
let slot = vm.readDU8()
vm.stack[slot + frameBottom] = vm.peek()
of opJumpIfFalse:
let offset = vm.readTriple()
let offset = vm.readDU8()
if vm.peek.isFalsey:
vm.ii += offset
of opJumpIfFalsePop:
let offset = vm.readTriple()
let offset = vm.readDU8()
if vm.pop.isFalsey:
vm.ii += offset
of opJump:
let offset = vm.readTriple()
let offset = vm.readDU8()
vm.ii += offset
of opLoop:
let offset = vm.readTriple()
let offset = vm.readDU8()
vm.ii -= offset
of opCall:
# create the call env
@ -181,7 +181,7 @@ proc run*(vm: VM): InterpretResult =
# ... <funct obj> <arg1> <arg2> <arg3>
# opCall converts it to this
# ... <ret val> <arg1> <arg2> <arg3>
let argcount = vm.readTriple()
let argcount = vm.readDU8()
let funct = vm.stack[vm.stack.high - argcount]
if funct.konType != ktFunct:
vm.runtimeError("Attempt to call a non-funct (a defunct?).") # here is a bad defunct joke