new VM: implemented constructors and jump optimizer

This commit is contained in:
Araq
2013-08-07 01:40:08 +02:00
parent ee9aee6c00
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.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
# ordinal
var x = getInt(a)

View File

@@ -12,7 +12,7 @@
import
strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
parser, vmdeps
parser, vmdeps, idents
from semfold import leValueConv
@@ -87,12 +87,6 @@ template decodeBx(k: expr) {.immediate, dirty.} =
let rbx = instr.regBx - wordExcess
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)
# XXX fix minor 'shallowCopy' overloading bug in compiler
@@ -666,7 +660,38 @@ proc execute(c: PCtx, start: int) =
of opcNLineInfo:
let rb = instr.regB
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:
InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
inc pc

View File

@@ -86,6 +86,9 @@ type
opcNWarning,
opcNHint,
opcNLineInfo,
opcEqIdent,
opcStrToIdent,
opcIdentToStr,
opcEcho,
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
@@ -114,7 +117,8 @@ type
opcLdGlobal, # dest = globals[Bx]
opcLdImmInt, # dest = immediate value
opcWrGlobal,
opcWrGlobalRef
opcWrGlobalRef,
opcSetType # dest.typ = types[Bx]
TBlock* = object
label*: PSym

View File

@@ -7,7 +7,7 @@
# 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 =
result = ""
@@ -35,6 +35,35 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
result = ""
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:
proc opExpandToAst*(c: PEvalContext, original: PNode): PNode =
var

View File

@@ -11,7 +11,7 @@
import
unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef,
trees, intsets, rodread
trees, intsets, rodread, magicsys
proc codeListing(c: PCtx, result: var string) =
# 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.} =
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 t = genType(c, n.typ)
c.gABx(n, opcSetType, tmp, genType(c, arg.typ))
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opc, dest, tmp)
c.gABx(n, opc, 0, t)
c.gABx(n, opc, 0, genType(c, n.typ))
c.freeTemp(tmp)
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 mNCopyNimTree: InternalError(n.info, "cannot generate code for: " & $m)
of mNBindSym: genUnaryABC(c, n, dest, opcNBindSym)
of mStrToIdent: InternalError(n.info, "cannot generate code for: " & $m)
of mIdentToStr: InternalError(n.info, "cannot generate code for: " & $m)
of mEqIdent: InternalError(n.info, "cannot generate code for: " & $m)
of mEqNimrodNode: InternalError(n.info, "cannot generate code for: " & $m)
of mNLineInfo: InternalError(n.info, "cannot generate code for: " & $m)
of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
of mIdentToStr: genUnaryABC(c, n, dest, opcIdentToStr)
of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqRef)
of mNLineInfo: genUnaryABC(c, n, dest, opcNLineInfo)
of mNHint:
unused(n, dest)
genUnaryStmt(c, n, opcNHint)
@@ -946,6 +946,63 @@ proc genVarSection(c: PCtx; n: PNode) =
else:
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 gen(c: PCtx; n: PNode; dest: var TDest) =
@@ -1048,8 +1105,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
unused(n, dest)
of nkStringToCString, nkCStringToString:
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:
#of nkCurly, nkBracket, nkPar:
InternalError n.info, "too implement " & $n.kind
proc removeLastEof(c: PCtx) =
@@ -1076,6 +1136,51 @@ proc genParams(c: PCtx; params: PNode) =
c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
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 =
let x = s.ast.sons[optimizedCodePos]
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
case mode
of fmRead, fmReadWriteExisting, fmAppend: flags = 0
of fmWrite:
of fmWrite:
if existsFile(filename): removeFile(filename)
flags = ZIP_CREATE or ZIP_EXCL
of fmReadWrite: flags = ZIP_CREATE

View File

@@ -4,10 +4,9 @@ version 0.9.4
- new VM:
- implement opcConv
- implement missing magics
- implement constructors
- implement overflow checking
- implement the glue to replace evals.nim
- implement on the fly CSE
- implement a jump optimizer
- make 'bind' default for templates and introduce 'mixin'
- special rule for ``[]=``
@@ -17,6 +16,7 @@ version 0.9.4
- overloading of ``.``? Special case ``.=``?
- built-in 'getImpl'
- optimize 'genericReset'; 'newException' leads to code bloat
- stack-less GC
Bugs