mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
new VM: implemented constructors and jump optimizer
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
4
todo.txt
4
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
|
||||
|
||||
Reference in New Issue
Block a user