new VM: implemented constructors and jump optimizer

This commit is contained in:
Araq 2013-08-07 01:40:08 +02:00
commit aefa0da8a6
7 changed files with 187 additions and 24 deletions

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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