new VM: implemented constructors and jump optimizer
This commit is contained in:
parent
ee9aee6c00
commit
aefa0da8a6
7 changed files with 187 additions and 24 deletions
|
|
@ -51,7 +51,7 @@ proc newStrNodeT(strVal: string, n: PNode): PNode =
|
||||||
result.typ = n.typ
|
result.typ = n.typ
|
||||||
result.info = n.info
|
result.info = n.info
|
||||||
|
|
||||||
proc ordinalValToString(a: PNode): string =
|
proc ordinalValToString*(a: PNode): string =
|
||||||
# because $ has the param ordinal[T], `a` is not necessarily an enum, but an
|
# because $ has the param ordinal[T], `a` is not necessarily an enum, but an
|
||||||
# ordinal
|
# ordinal
|
||||||
var x = getInt(a)
|
var x = getInt(a)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
|
strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
|
||||||
parser, vmdeps
|
parser, vmdeps, idents
|
||||||
|
|
||||||
from semfold import leValueConv
|
from semfold import leValueConv
|
||||||
|
|
||||||
|
|
@ -87,12 +87,6 @@ template decodeBx(k: expr) {.immediate, dirty.} =
|
||||||
let rbx = instr.regBx - wordExcess
|
let rbx = instr.regBx - wordExcess
|
||||||
ensureKind(k)
|
ensureKind(k)
|
||||||
|
|
||||||
proc myreset(n: PNode) =
|
|
||||||
when defined(system.reset):
|
|
||||||
var oldInfo = n.info
|
|
||||||
reset(n[])
|
|
||||||
n.info = oldInfo
|
|
||||||
|
|
||||||
template move(a, b: expr) = system.shallowCopy(a, b)
|
template move(a, b: expr) = system.shallowCopy(a, b)
|
||||||
# XXX fix minor 'shallowCopy' overloading bug in compiler
|
# XXX fix minor 'shallowCopy' overloading bug in compiler
|
||||||
|
|
||||||
|
|
@ -666,7 +660,38 @@ proc execute(c: PCtx, start: int) =
|
||||||
of opcNLineInfo:
|
of opcNLineInfo:
|
||||||
let rb = instr.regB
|
let rb = instr.regB
|
||||||
let n = regs[rb]
|
let n = regs[rb]
|
||||||
regs[ra] = newStrNodeT(n.info.toFileLineCol, n)
|
regs[ra] = newStrNode(nkStrLit, n.info.toFileLineCol)
|
||||||
|
regs[ra].info = c.debug[pc]
|
||||||
|
of opcEqIdent:
|
||||||
|
decodeBC(nkIntLit)
|
||||||
|
if regs[rb].kind == nkIdent and regs[rc].kind == nkIdent:
|
||||||
|
regs[ra].intVal = ord(regs[rb].ident.id == regs[rc].ident.id)
|
||||||
|
else:
|
||||||
|
regs[ra].intVal = 0
|
||||||
|
of opcStrToIdent:
|
||||||
|
let rb = instr.regB
|
||||||
|
if regs[rb].kind notin {nkStrLit..nkTripleStrLit}:
|
||||||
|
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
||||||
|
else:
|
||||||
|
regs[ra] = newNodeI(nkIdent, c.debug[pc])
|
||||||
|
regs[ra].ident = getIdent(regs[rb].strVal)
|
||||||
|
of opcIdentToStr:
|
||||||
|
let rb = instr.regB
|
||||||
|
let a = regs[rb]
|
||||||
|
regs[ra] = newNodeI(nkStrLit, c.debug[pc])
|
||||||
|
if a.kind == nkSym:
|
||||||
|
regs[ra].strVal = a.sym.name.s
|
||||||
|
elif a.kind == nkIdent:
|
||||||
|
regs[ra].strVal = a.ident.s
|
||||||
|
else:
|
||||||
|
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
|
||||||
|
of opcSetType:
|
||||||
|
regs[ra].typ = c.types[instr.regBx - wordExcess]
|
||||||
|
of opcConv:
|
||||||
|
let rb = instr.regB
|
||||||
|
inc pc
|
||||||
|
let typ = c.types[c.code[pc].regBx - wordExcess]
|
||||||
|
opConv(regs[ra], regs[rb], typ)
|
||||||
else:
|
else:
|
||||||
InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
|
InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
|
||||||
inc pc
|
inc pc
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,9 @@ type
|
||||||
opcNWarning,
|
opcNWarning,
|
||||||
opcNHint,
|
opcNHint,
|
||||||
opcNLineInfo,
|
opcNLineInfo,
|
||||||
|
opcEqIdent,
|
||||||
|
opcStrToIdent,
|
||||||
|
opcIdentToStr,
|
||||||
|
|
||||||
opcEcho,
|
opcEcho,
|
||||||
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||||
|
|
@ -114,7 +117,8 @@ type
|
||||||
opcLdGlobal, # dest = globals[Bx]
|
opcLdGlobal, # dest = globals[Bx]
|
||||||
opcLdImmInt, # dest = immediate value
|
opcLdImmInt, # dest = immediate value
|
||||||
opcWrGlobal,
|
opcWrGlobal,
|
||||||
opcWrGlobalRef
|
opcWrGlobalRef,
|
||||||
|
opcSetType # dest.typ = types[Bx]
|
||||||
|
|
||||||
TBlock* = object
|
TBlock* = object
|
||||||
label*: PSym
|
label*: PSym
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
import ast, msgs, osproc, streams, options
|
import ast, types, msgs, osproc, streams, options, semfold
|
||||||
|
|
||||||
proc readOutput(p: PProcess): string =
|
proc readOutput(p: PProcess): string =
|
||||||
result = ""
|
result = ""
|
||||||
|
|
@ -35,6 +35,35 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
|
||||||
result = ""
|
result = ""
|
||||||
LocalError(info, errCannotOpenFile, file)
|
LocalError(info, errCannotOpenFile, file)
|
||||||
|
|
||||||
|
proc myreset*(n: PNode) =
|
||||||
|
when defined(system.reset):
|
||||||
|
var oldInfo = n.info
|
||||||
|
reset(n[])
|
||||||
|
n.info = oldInfo
|
||||||
|
|
||||||
|
proc opConv*(dest, src: PNode, typ: PType) =
|
||||||
|
if typ.kind == tyString:
|
||||||
|
if dest.kind != nkStrLit:
|
||||||
|
myreset(dest)
|
||||||
|
dest.kind = nkStrLit
|
||||||
|
case src.typ.skipTypes(abstractRange).kind
|
||||||
|
of tyEnum:
|
||||||
|
dest.strVal = ordinalValToString(src)
|
||||||
|
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||||
|
dest.strVal = $src.intVal
|
||||||
|
of tyBool:
|
||||||
|
dest.strVal = if src.intVal == 0: "false" else: "true"
|
||||||
|
of tyFloat..tyFloat128:
|
||||||
|
dest.strVal = $src.floatVal
|
||||||
|
of tyString, tyCString:
|
||||||
|
dest.strVal = src.strVal
|
||||||
|
of tyChar:
|
||||||
|
dest.strVal = $chr(src.intVal)
|
||||||
|
else:
|
||||||
|
internalError("cannot convert to string " & typ.typeToString)
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
proc opExpandToAst*(c: PEvalContext, original: PNode): PNode =
|
proc opExpandToAst*(c: PEvalContext, original: PNode): PNode =
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef,
|
unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef,
|
||||||
trees, intsets, rodread
|
trees, intsets, rodread, magicsys
|
||||||
|
|
||||||
proc codeListing(c: PCtx, result: var string) =
|
proc codeListing(c: PCtx, result: var string) =
|
||||||
# first iteration: compute all necessary labels:
|
# first iteration: compute all necessary labels:
|
||||||
|
|
@ -456,12 +456,12 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
proc unused(n: PNode; x: TDest) {.inline.} =
|
proc unused(n: PNode; x: TDest) {.inline.} =
|
||||||
if x >= 0: InternalError(n.info, "not unused")
|
if x >= 0: InternalError(n.info, "not unused")
|
||||||
|
|
||||||
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
||||||
let tmp = c.genx(arg)
|
let tmp = c.genx(arg)
|
||||||
let t = genType(c, n.typ)
|
c.gABx(n, opcSetType, tmp, genType(c, arg.typ))
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
c.gABC(n, opc, dest, tmp)
|
c.gABC(n, opc, dest, tmp)
|
||||||
c.gABx(n, opc, 0, t)
|
c.gABx(n, opc, 0, genType(c, n.typ))
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
|
|
@ -685,11 +685,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
of mNCopyNimNode: InternalError(n.info, "cannot generate code for: " & $m)
|
of mNCopyNimNode: InternalError(n.info, "cannot generate code for: " & $m)
|
||||||
of mNCopyNimTree: InternalError(n.info, "cannot generate code for: " & $m)
|
of mNCopyNimTree: InternalError(n.info, "cannot generate code for: " & $m)
|
||||||
of mNBindSym: genUnaryABC(c, n, dest, opcNBindSym)
|
of mNBindSym: genUnaryABC(c, n, dest, opcNBindSym)
|
||||||
of mStrToIdent: InternalError(n.info, "cannot generate code for: " & $m)
|
of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
|
||||||
of mIdentToStr: InternalError(n.info, "cannot generate code for: " & $m)
|
of mIdentToStr: genUnaryABC(c, n, dest, opcIdentToStr)
|
||||||
of mEqIdent: InternalError(n.info, "cannot generate code for: " & $m)
|
of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
|
||||||
of mEqNimrodNode: InternalError(n.info, "cannot generate code for: " & $m)
|
of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqRef)
|
||||||
of mNLineInfo: InternalError(n.info, "cannot generate code for: " & $m)
|
of mNLineInfo: genUnaryABC(c, n, dest, opcNLineInfo)
|
||||||
of mNHint:
|
of mNHint:
|
||||||
unused(n, dest)
|
unused(n, dest)
|
||||||
genUnaryStmt(c, n, opcNHint)
|
genUnaryStmt(c, n, opcNHint)
|
||||||
|
|
@ -946,6 +946,63 @@ proc genVarSection(c: PCtx; n: PNode) =
|
||||||
else:
|
else:
|
||||||
genAsgn(c, a.sons[0], a.sons[2], true)
|
genAsgn(c, a.sons[0], a.sons[2], true)
|
||||||
|
|
||||||
|
proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
|
||||||
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
c.gABx(n, opcLdNull, dest, c.genType(n.typ))
|
||||||
|
let intType = getSysType(tyInt)
|
||||||
|
var tmp = getTemp(c, intType)
|
||||||
|
c.gABx(n, opcLdNull, tmp, c.genType(intType))
|
||||||
|
for x in n:
|
||||||
|
let a = c.genx(x)
|
||||||
|
c.gABC(n, opcWrArr, dest, a, tmp)
|
||||||
|
c.gABI(n, opcAddImmInt, tmp, tmp, 1)
|
||||||
|
c.freeTemp(a)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
|
proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
|
||||||
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
c.gABx(n, opcLdNull, dest, c.genType(n.typ))
|
||||||
|
for x in n:
|
||||||
|
let a = c.genx(x)
|
||||||
|
c.gABC(n, opcIncl, dest, a)
|
||||||
|
c.freeTemp(a)
|
||||||
|
|
||||||
|
proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
|
||||||
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
let t = n.typ.skipTypes(abstractRange)
|
||||||
|
if t.kind == tyRef:
|
||||||
|
c.gABx(n, opcNew, dest, c.genType(t.sons[0]))
|
||||||
|
else:
|
||||||
|
c.gABx(n, opcLdNull, dest, c.genType(n.typ))
|
||||||
|
for i in 1.. <n.len:
|
||||||
|
let it = n.sons[i]
|
||||||
|
if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
|
||||||
|
let idx = c.genx(it.sons[0])
|
||||||
|
let tmp = c.genx(it.sons[1])
|
||||||
|
c.gABC(it, whichAsgnOpc(it.sons[1], opcWrObj), dest, idx, tmp)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(idx)
|
||||||
|
else:
|
||||||
|
internalError(n.info, "invalid object constructor")
|
||||||
|
|
||||||
|
proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
|
||||||
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
var idx = getTemp(c, getSysType(tyInt))
|
||||||
|
for i in 0.. <n.len:
|
||||||
|
let it = n.sons[i]
|
||||||
|
if it.kind == nkExprColonExpr:
|
||||||
|
let idx = c.genx(it.sons[0])
|
||||||
|
let tmp = c.genx(it.sons[1])
|
||||||
|
c.gABC(it, whichAsgnOpc(it.sons[1], opcWrObj), dest, idx, tmp)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(idx)
|
||||||
|
else:
|
||||||
|
let tmp = c.genx(it)
|
||||||
|
c.gABx(it, opcLdImmInt, idx, i)
|
||||||
|
c.gABC(it, whichAsgnOpc(it, opcWrObj), dest, idx, tmp)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(idx)
|
||||||
|
|
||||||
proc genProc*(c: PCtx; s: PSym): int
|
proc genProc*(c: PCtx; s: PSym): int
|
||||||
|
|
||||||
proc gen(c: PCtx; n: PNode; dest: var TDest) =
|
proc gen(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
|
|
@ -1048,8 +1105,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
unused(n, dest)
|
unused(n, dest)
|
||||||
of nkStringToCString, nkCStringToString:
|
of nkStringToCString, nkCStringToString:
|
||||||
gen(c, n.sons[0], dest)
|
gen(c, n.sons[0], dest)
|
||||||
|
of nkBracket: genArrayConstr(c, n, dest)
|
||||||
|
of nkCurly: genSetConstr(c, n, dest)
|
||||||
|
of nkObjConstr: genObjConstr(c, n, dest)
|
||||||
|
of nkPar, nkClosure: genTupleConstr(c, n, dest)
|
||||||
else:
|
else:
|
||||||
#of nkCurly, nkBracket, nkPar:
|
|
||||||
InternalError n.info, "too implement " & $n.kind
|
InternalError n.info, "too implement " & $n.kind
|
||||||
|
|
||||||
proc removeLastEof(c: PCtx) =
|
proc removeLastEof(c: PCtx) =
|
||||||
|
|
@ -1076,6 +1136,51 @@ proc genParams(c: PCtx; params: PNode) =
|
||||||
c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
|
c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
|
||||||
c.prc.maxSlots = max(params.len, 1)
|
c.prc.maxSlots = max(params.len, 1)
|
||||||
|
|
||||||
|
proc finalJumpTarget(c: PCtx; pc, diff: int) =
|
||||||
|
InternalAssert(-0x7fff < diff and diff < 0x7fff)
|
||||||
|
let oldInstr = c.code[pc]
|
||||||
|
# opcode and regA stay the same:
|
||||||
|
c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
|
||||||
|
uint32(diff+wordExcess) shl 16'u32).TInstr
|
||||||
|
|
||||||
|
proc optimizeJumps(c: PCtx; start: int) =
|
||||||
|
const maxIterations = 10
|
||||||
|
for i in start .. <c.code.len:
|
||||||
|
let opc = c.code[i].opcode
|
||||||
|
case opc
|
||||||
|
of opcTJmp, opcFJmp:
|
||||||
|
var reg = c.code[i].regA
|
||||||
|
var d = i + c.code[i].regBx
|
||||||
|
var iters = maxIterations
|
||||||
|
while iters > 0:
|
||||||
|
case c.code[d].opcode
|
||||||
|
of opcJmp:
|
||||||
|
d = d + c.code[d].regBx
|
||||||
|
of opcTJmp, opcFJmp:
|
||||||
|
if c.code[d].regA != reg: break
|
||||||
|
# tjmp x, 23
|
||||||
|
# ...
|
||||||
|
# tjmp x, 12
|
||||||
|
# -- we know 'x' is true, and so can jump to 12+13:
|
||||||
|
if c.code[d].opcode == opc:
|
||||||
|
d = d + c.code[d].regBx
|
||||||
|
else:
|
||||||
|
# tjmp x, 23
|
||||||
|
# fjmp x, 22
|
||||||
|
# We know 'x' is true so skip to the next instruction:
|
||||||
|
d = d + 1
|
||||||
|
else: break
|
||||||
|
dec iters
|
||||||
|
c.finalJumpTarget(i, d - i)
|
||||||
|
of opcJmp:
|
||||||
|
var d = i + c.code[i].regBx
|
||||||
|
var iters = maxIterations
|
||||||
|
while c.code[d].opcode == opcJmp and iters > 0:
|
||||||
|
d = d + c.code[d].regBx
|
||||||
|
dec iters
|
||||||
|
c.finalJumpTarget(i, d - i)
|
||||||
|
else: discard
|
||||||
|
|
||||||
proc genProc(c: PCtx; s: PSym): int =
|
proc genProc(c: PCtx; s: PSym): int =
|
||||||
let x = s.ast.sons[optimizedCodePos]
|
let x = s.ast.sons[optimizedCodePos]
|
||||||
if x.kind == nkEmpty:
|
if x.kind == nkEmpty:
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ proc open*(z: var TZipArchive, filename: string, mode: TFileMode = fmRead): bool
|
||||||
var err, flags: int32
|
var err, flags: int32
|
||||||
case mode
|
case mode
|
||||||
of fmRead, fmReadWriteExisting, fmAppend: flags = 0
|
of fmRead, fmReadWriteExisting, fmAppend: flags = 0
|
||||||
of fmWrite:
|
of fmWrite:
|
||||||
if existsFile(filename): removeFile(filename)
|
if existsFile(filename): removeFile(filename)
|
||||||
flags = ZIP_CREATE or ZIP_EXCL
|
flags = ZIP_CREATE or ZIP_EXCL
|
||||||
of fmReadWrite: flags = ZIP_CREATE
|
of fmReadWrite: flags = ZIP_CREATE
|
||||||
|
|
|
||||||
4
todo.txt
4
todo.txt
|
|
@ -4,10 +4,9 @@ version 0.9.4
|
||||||
- new VM:
|
- new VM:
|
||||||
- implement opcConv
|
- implement opcConv
|
||||||
- implement missing magics
|
- implement missing magics
|
||||||
- implement constructors
|
- implement overflow checking
|
||||||
- implement the glue to replace evals.nim
|
- implement the glue to replace evals.nim
|
||||||
- implement on the fly CSE
|
- implement on the fly CSE
|
||||||
- implement a jump optimizer
|
|
||||||
|
|
||||||
- make 'bind' default for templates and introduce 'mixin'
|
- make 'bind' default for templates and introduce 'mixin'
|
||||||
- special rule for ``[]=``
|
- special rule for ``[]=``
|
||||||
|
|
@ -17,6 +16,7 @@ version 0.9.4
|
||||||
- overloading of ``.``? Special case ``.=``?
|
- overloading of ``.``? Special case ``.=``?
|
||||||
- built-in 'getImpl'
|
- built-in 'getImpl'
|
||||||
- optimize 'genericReset'; 'newException' leads to code bloat
|
- optimize 'genericReset'; 'newException' leads to code bloat
|
||||||
|
- stack-less GC
|
||||||
|
|
||||||
|
|
||||||
Bugs
|
Bugs
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue