optimalization: op popn

This commit is contained in:
prod2 2022-01-27 03:32:42 +01:00
parent 9fed85928d
commit d64a63dc27
3 changed files with 55 additions and 16 deletions

View File

@ -6,7 +6,7 @@ import value
type
OpCode* = enum
opReturn, opCall, # functions
opPop, # pop
opPop, opPopSA, opPopA # pop
opPrint, # print
opNegate, opNot # unary
opAdd, opSubtract, opMultiply, opDivide, # math
@ -25,8 +25,14 @@ type
DoubleUint8* = array[2, uint8]
# WARNING! short args can safely assumed to be 1 byte long outside of chunk.nim
const shortArgSize* = 1
const shortArgMax* = 256 # despite the name, this is one larger than the max
# modules outside chunk.nim should not assume any length of argSize, however code inside chunk.nim can make such assumptions
const argSize* = 2
const argMax*: int = 256*256
const argMax*: int = 256*256 # despite the name, this is one larger than the max
proc initChunk*(name: string): Chunk =
Chunk(code: @[], name: name, lines: @[], constants: @[])
@ -78,7 +84,11 @@ const constantInstructions = {
opConstant,
opDefineGlobal, opGetGlobal, opSetGlobal,
}
const shortArgInstructions = {
opPopSA,
}
const argInstructions = {
opPopA,
opCall,
opGetLocal, opSetLocal,
opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop,
@ -94,6 +104,7 @@ proc disassembleChunk*(ch: Chunk) =
template instruction: uint8 = ch.code[c]
template line: int = ch.lines[c]
template double: DoubleUint8 = [ch.code[c+1], ch.code[c+2]]
template shortArg: uint8 = ch.code[c+1]
let cFmt = &"{c:04}"
let lineFmt = if lastLine == line: " | " else: &"{line:04}"
try:
@ -101,6 +112,9 @@ proc disassembleChunk*(ch: Chunk) =
case instruction.OpCode:
of simpleInstructions:
write stdout, ")\n"
of shortArgInstructions:
write stdout, &" {shortArg.toHex(2)}"
c += 1
of argInstructions:
write stdout, &" {double[0].toHex(2)} {double[1].toHex(2)})\n"
c += 2

View File

@ -131,12 +131,30 @@ proc synchronize(comp: Compiler) =
return
comp.advance()
proc writeChunk(comp: Compiler, dStackIndex: int, ch: OpCode | DoubleUint8) =
proc writeChunk(comp: Compiler, dStackIndex: int, ch: OpCode | DoubleUint8 | uint8) =
comp.stackIndex += dStackIndex
when debugCompiler:
debugEcho &"new stackindex: {comp.stackIndex}, delta: {dStackIndex} due to {ch.repr}"
comp.chunk.writeChunk(ch, comp.previous.line)
proc writePops(comp: Compiler, count: int) =
if count > argMax:
comp.error("Too many local variables in block.")
if count == 0:
return
when debugCompiler:
debugEcho &"Emitting {count}xPop."
if count == 1:
comp.writeChunk(-1, opPop)
elif count < shortArgMax:
comp.writeChunk(-count, opPopSA)
comp.writeChunk(0, count.uint8)
else:
comp.writeChunk(-count, opPopA)
comp.writeChunk(0, count.toDU8())
proc writeConstant(comp: Compiler, constant: KonValue) =
comp.stackIndex.inc
let index = comp.chunk.writeConstant(constant, comp.previous.line)
@ -248,8 +266,7 @@ proc beginScope(comp: Compiler, function: bool = false) =
proc restore(comp: Compiler, scope: Scope) =
let delta = comp.stackIndex - scope.goalStackIndex
for i in countup(1, delta):
comp.writeChunk(-1, opPop)
comp.writePops(delta)
when assertionsCompiler:
if not comp.stackIndex == scope.goalStackIndex:
comp.error("Assertion failed in restore")
@ -257,15 +274,9 @@ proc restore(comp: Compiler, scope: Scope) =
debugEcho &"Restored scope: delta {delta}"
proc restoreInFunct(comp: Compiler, scope: Scope) =
when debugCompiler:
var pops = 0
while comp.stackIndex > 0:
comp.writeChunk(-1, opPop)
when debugCompiler:
inc pops
when assertionsCompiler:
if not comp.stackIndex == 0:
comp.error("Assertion failed in restoreInFunct")
let pops = comp.stackIndex
comp.writePops(pops)
comp.stackIndex = scope.goalStackIndex
when debugCompiler:
@ -273,8 +284,7 @@ proc restoreInFunct(comp: Compiler, scope: Scope) =
proc jumpToEnd(comp: Compiler, scope: Scope) =
let delta = comp.stackIndex - scope.goalStackIndex
for i in countup(1, delta):
comp.writeChunk(0, opPop)
comp.writePops(delta)
let jmp = comp.emitJump(0, opJump)
scope.jumps.add(jmp)

15
vm.nim
View File

@ -42,6 +42,10 @@ proc run*(chunk: Chunk): InterpretResult =
template peek(stack: seq[KonValue]): KonValue =
stack[stack.high]
proc popn(stack: var seq[KonValue], amt: int) {.inline.} =
for i in countup(1, amt):
discard stack.pop()
proc pushSafe(stack: var seq[KonValue], val: KonValue): bool =
## returns if the value is not a runtime error
## prints the error if it is a runtime error
@ -53,6 +57,10 @@ proc run*(chunk: Chunk): InterpretResult =
stack.add(val)
true
proc readUI8(): int =
result = ip[].int
ip = ip.padd(1)
proc readDU8(): int =
result = ip.DU8ptrToInt
ip = ip.padd(argSize)
@ -60,6 +68,7 @@ proc run*(chunk: Chunk): InterpretResult =
proc readConstant(): KonValue =
let index = readDU8()
chunk.constants[index]
template frameBottom: int = frames[frames.high].stackBottom
while true:
@ -88,6 +97,12 @@ proc run*(chunk: Chunk): InterpretResult =
case ins:
of opPop:
discard stack.pop()
of opPopA:
let amt = readDU8()
stack.popn(amt)
of opPopSA:
let amt = readUI8()
stack.popn(amt)
of opConstant:
let val: KonValue = readConstant()
stack.add(val)