diff options
author | Araq <rumpf_a@web.de> | 2013-08-07 01:40:08 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2013-08-07 01:40:08 +0200 |
commit | aefa0da8a612df3bb363435dd78ed641b239c0c8 (patch) | |
tree | f51f7e8a3c4711b75280eb8e290ac2906c3032f6 | |
parent | ee9aee6c0082e990d6b7355730704bdf6c70288c (diff) | |
download | Nim-aefa0da8a612df3bb363435dd78ed641b239c0c8.tar.gz |
new VM: implemented constructors and jump optimizer
-rw-r--r-- | compiler/semfold.nim | 2 | ||||
-rw-r--r-- | compiler/vm.nim | 41 | ||||
-rw-r--r-- | compiler/vmdef.nim | 6 | ||||
-rw-r--r-- | compiler/vmdeps.nim | 31 | ||||
-rw-r--r-- | compiler/vmgen.nim | 125 | ||||
-rw-r--r-- | lib/impure/zipfiles.nim | 2 | ||||
-rw-r--r-- | todo.txt | 4 |
7 files changed, 187 insertions, 24 deletions
diff --git a/compiler/semfold.nim b/compiler/semfold.nim index c9d2575cb..77ecf2e97 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -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) diff --git a/compiler/vm.nim b/compiler/vm.nim index 7929774ee..86d1fbe07 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -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 diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 1a19efe5a..90d23e642 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -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 diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 2a9929de0..7a645aca9 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -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 diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index c5bfa3095..2033fb23c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -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: diff --git a/lib/impure/zipfiles.nim b/lib/impure/zipfiles.nim index 029d8527d..de73b500d 100644 --- a/lib/impure/zipfiles.nim +++ b/lib/impure/zipfiles.nim @@ -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 diff --git a/todo.txt b/todo.txt index 5b6cca2bb..dff9b5770 100644 --- a/todo.txt +++ b/todo.txt @@ -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 |