new VM: register allocator bugfix; implemented more magics

This commit is contained in:
Araq
2013-08-08 21:10:54 +02:00
parent 06b3852143
commit 288cd05f89
5 changed files with 195 additions and 64 deletions

View File

@@ -14,7 +14,7 @@ import
strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
parser, vmdeps, idents
from semfold import leValueConv
from semfold import leValueConv, ordinalValToString
type
PStackFrame* = ref TStackFrame
@@ -60,6 +60,12 @@ when not defined(nimHasInterpreterLoop):
template inc(pc: ptr TInstr, diff = 1) =
inc cast[TAddress](pc), TInstr.sizeof * diff
proc myreset(n: PNode) =
when defined(system.reset):
var oldInfo = n.info
reset(n[])
n.info = oldInfo
template ensureKind(k: expr) {.immediate, dirty.} =
if regs[ra].kind != k:
myreset(regs[ra])
@@ -170,6 +176,57 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
return pc
return -1
proc opConv*(dest, src: PNode, typ: PType): bool =
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:
case skipTypes(typ, abstractRange).kind
of tyInt..tyInt64:
if dest.kind != nkIntLit:
myreset(dest); dest.kind = nkIntLit
case skipTypes(src.typ, abstractRange).kind
of tyFloat..tyFloat64:
dest.intVal = system.toInt(src.floatVal)
else:
dest.intVal = src.intVal
if dest.intVal < firstOrd(typ) or dest.intVal > lastOrd(typ):
return true
of tyUInt..tyUInt64:
if dest.kind != nkIntLit:
myreset(dest); dest.kind = nkIntLit
case skipTypes(src.typ, abstractRange).kind
of tyFloat..tyFloat64:
dest.intVal = system.toInt(src.floatVal)
else:
dest.intVal = src.intVal and ((1 shl typ.size)-1)
of tyFloat..tyFloat64:
if dest.kind != nkFloatLit:
myreset(dest); dest.kind = nkFloatLit
case skipTypes(src.typ, abstractRange).kind
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar:
dest.floatVal = toFloat(src.intVal.int)
else:
dest.floatVal = src.floatVal
else:
asgnComplex(dest, src)
proc compile(c: PCtx, s: PSym): int =
result = vmgen.genProc(c, s)
#c.echoCode
@@ -243,6 +300,7 @@ proc execute(c: PCtx, start: int) =
let rb = instr.regB
let rc = instr.regC
# XXX this creates a wrong alias
#Message(c.debug[pc], warnUser, $regs[rb].len & " " & $rc)
asgnComplex(regs[ra], regs[rb].sons[rc])
of opcWrObj:
# a.b = c
@@ -380,8 +438,9 @@ proc execute(c: PCtx, start: int) =
regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
of opcEqRef:
decodeBC(nkIntLit)
regs[ra].intVal = ord(regs[rb] == regs[rc])
# XXX is this correct? nope ...
regs[ra].intVal = ord((regs[rb].kind == nkNilLit and
regs[rc].kind == nkNilLit) or
regs[rb].sons == regs[rc].sons)
of opcXor:
decodeBC(nkIntLit)
regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
@@ -448,7 +507,11 @@ proc execute(c: PCtx, start: int) =
decodeB(nkBracket)
regs[ra].add(copyTree(regs[rb]))
of opcEcho:
echo regs[ra].strVal
let rb = instr.regB
for i in ra..ra+rb-1:
if regs[i].kind != nkStrLit: debug regs[i]
write(stdout, regs[i].strVal)
writeln(stdout, "")
of opcContainsSet:
decodeBC(nkIntLit)
regs[ra].intVal = Ord(inSet(regs[rb], regs[rc]))
@@ -691,7 +754,62 @@ proc execute(c: PCtx, start: int) =
let rb = instr.regB
inc pc
let typ = c.types[c.code[pc].regBx - wordExcess]
opConv(regs[ra], regs[rb], typ)
if opConv(regs[ra], regs[rb], typ):
stackTrace(c, tos, pc, errGenerated,
msgKindToString(errIllegalConvFromXtoY) % [
"unknown type" , "unknown type"])
of opcNSetIntVal:
let rb = instr.regB
if regs[ra].kind in {nkCharLit..nkInt64Lit} and
regs[rb].kind in {nkCharLit..nkInt64Lit}:
regs[ra].intVal = regs[rb].intVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
of opcNSetFloatVal:
let rb = instr.regB
if regs[ra].kind in {nkFloatLit..nkFloat64Lit} and
regs[rb].kind in {nkFloatLit..nkFloat64Lit}:
regs[ra].floatVal = regs[rb].floatVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
of opcNSetSymbol:
let rb = instr.regB
if regs[ra].kind == nkSym and regs[rb].kind == nkSym:
regs[ra].sym = regs[rb].sym
else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
of opcNSetIdent:
let rb = instr.regB
if regs[ra].kind == nkIdent and regs[rb].kind == nkIdent:
regs[ra].ident = regs[rb].ident
else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
of opcNSetType:
let b = regs[instr.regB]
InternalAssert b.kind == nkSym and b.sym.kind == skType
regs[ra].typ = b.sym.typ
of opcNSetStrVal:
let rb = instr.regB
if regs[ra].kind in {nkStrLit..nkTripleStrLit} and
regs[rb].kind in {nkStrLit..nkTripleStrLit}:
regs[ra].strVal = regs[rb].strVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
of opcNNewNimNode:
let rb = instr.regB
let rc = instr.regC
var k = regs[rb].intVal
if k < 0 or k > ord(high(TNodeKind)):
internalError(c.debug[pc],
"request to create a NimNode with invalid kind")
regs[ra] = newNodeI(TNodeKind(int(k)),
if regs[rc].kind == nkNilLit: c.debug[pc] else: regs[rc].info)
of opcNCopyNimNode:
let rb = instr.regB
regs[ra] = copyNode(regs[rb])
of opcNCopyNimTree:
let rb = instr.regB
regs[ra] = copyTree(regs[rb])
else:
InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
inc pc

View File

@@ -78,6 +78,10 @@ type
opcNGetType,
opcNStrVal,
opcNSetIntVal,
opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree,
opcSlurp,
opcGorge,
opcParseExprToAst,

View File

@@ -7,7 +7,7 @@
# distribution, for details about the copyright.
#
import ast, types, msgs, osproc, streams, options, semfold
import ast, types, msgs, osproc, streams, options
proc readOutput(p: PProcess): string =
result = ""
@@ -35,35 +35,6 @@ 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

@@ -137,14 +137,14 @@ proc getTempRange(c: PCtx; n: int; kind: TSlotKind): TRegister =
# if register pressure is high, we re-use more aggressively:
let c = c.prc
if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister):
for i in 0 .. c.maxSlots-1:
block search:
if not c.slots[i].inUse:
for i in 0 .. c.maxSlots-n:
if not c.slots[i].inUse:
block search:
for j in i+1 .. i+n-1:
if c.slots[j].inUse: break search
result = TRegister(i)
for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
return
result = TRegister(i)
for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
return
if c.maxSlots+n >= high(TRegister):
InternalError("cannot generate code; too many registers required")
result = TRegister(c.maxSlots)
@@ -186,6 +186,14 @@ proc genx(c: PCtx; n: PNode): TRegister =
gen(c, n, tmp)
result = TRegister(tmp)
proc isNotOpr(n: PNode): bool =
n.kind in nkCallKinds and n.sons[0].kind == nkSym and
n.sons[0].sym.magic == mNot
proc isTrue(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
proc genWhile(c: PCtx; n: PNode) =
# L1:
# cond, tmp
@@ -195,12 +203,23 @@ proc genWhile(c: PCtx; n: PNode) =
# L2:
let L1 = c.genLabel
withBlock(nil):
var tmp = c.genx(n.sons[0])
let L2 = c.xjmp(n, opcFJmp, tmp)
c.freeTemp(tmp)
c.gen(n.sons[1])
c.jmpBack(n, opcJmp, L1)
c.patch(L2)
if isTrue(n.sons[0]):
c.gen(n.sons[1])
c.jmpBack(n, opcJmp, L1)
elif isNotOpr(n.sons[0]):
var tmp = c.genx(n.sons[0].sons[1])
let L2 = c.xjmp(n, opcTJmp, tmp)
c.freeTemp(tmp)
c.gen(n.sons[1])
c.jmpBack(n, opcJmp, L1)
c.patch(L2)
else:
var tmp = c.genx(n.sons[0])
let L2 = c.xjmp(n, opcFJmp, tmp)
c.freeTemp(tmp)
c.gen(n.sons[1])
c.jmpBack(n, opcJmp, L1)
c.patch(L2)
proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
withBlock(n.sons[0].sym):
@@ -209,7 +228,7 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
proc genBreak(c: PCtx; n: PNode) =
let L1 = c.xjmp(n, opcJmp)
if n.sons[0].kind == nkSym:
echo cast[int](n.sons[0].sym)
#echo cast[int](n.sons[0].sym)
for i in countdown(c.prc.blocks.len-1, 0):
if c.prc.blocks[i].label == n.sons[0].sym:
c.prc.blocks[i].fixups.add L1
@@ -235,8 +254,13 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
var it = n.sons[i]
if it.len == 2:
withTemp(tmp, it.sons[0].typ):
c.gen(it.sons[0], tmp)
let elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false
var elsePos: TPosition
if isNotOpr(it.sons[0]):
c.gen(it.sons[0].sons[1], tmp)
elsePos = c.xjmp(it.sons[0].sons[1], opcTJmp, tmp) # if true
else:
c.gen(it.sons[0], tmp)
elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false
c.gen(it.sons[1], dest) # then part
if i < sonsLen(n)-1:
endings.add(c.xjmp(it.sons[1], opcJmp, 0))
@@ -629,11 +653,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
c.freeTemp(tmp)
of mEcho:
unused(n, dest)
let x = c.getTempRange(n.len-1, slotTempUnknown)
for i in 1.. <n.len:
var d = c.genx(n.sons[i])
c.gABC(n, opcEcho, d)
c.freeTemp(d)
of mAppendStrCh:
var r: TRegister = x+i-1
c.gen(n.sons[i], r)
c.gABC(n, opcEcho, x, n.len-1)
c.freeTempRange(x, n.len-1)
of mAppendStrCh:
unused(n, dest)
genBinaryStmt(c, n, opcAddStrCh)
of mAppendStrStr:
@@ -675,15 +701,27 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
of mNIdent: genUnaryABC(c, n, dest, opcNIdent)
of mNGetType: genUnaryABC(c, n, dest, opcNGetType)
of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
of mNSetIntVal: InternalError(n.info, "cannot generate code for: " & $m)
of mNSetFloatVal: InternalError(n.info, "cannot generate code for: " & $m)
of mNSetSymbol: InternalError(n.info, "cannot generate code for: " & $m)
of mNSetIdent: InternalError(n.info, "cannot generate code for: " & $m)
of mNSetType: InternalError(n.info, "cannot generate code for: " & $m)
of mNSetStrVal: InternalError(n.info, "cannot generate code for: " & $m)
of mNNewNimNode: 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 mNSetIntVal:
unused(n, dest)
genBinaryStmt(c, n, opcNSetIntVal)
of mNSetFloatVal:
unused(n, dest)
genBinaryStmt(c, n, opcNSetFloatVal)
of mNSetSymbol:
unused(n, dest)
genBinaryStmt(c, n, opcNSetSymbol)
of mNSetIdent:
unused(n, dest)
genBinaryStmt(c, n, opcNSetIdent)
of mNSetType:
unused(n, dest)
genBinaryStmt(c, n, opcNSetType)
of mNSetStrVal:
unused(n, dest)
genBinaryStmt(c, n, opcNSetStrVal)
of mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
of mNCopyNimTree: genUnaryABC(c, n, dest, opcNCopyNimTree)
of mNBindSym: genUnaryABC(c, n, dest, opcNBindSym)
of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
of mIdentToStr: genUnaryABC(c, n, dest, opcIdentToStr)
@@ -1203,5 +1241,6 @@ proc genProc(c: PCtx; s: PSym): int =
c.gABC(body, opcEof)
s.position = c.prc.maxSlots
c.prc = oldPrc
#c.echoCode
else:
result = x.intVal.int

View File

@@ -2,7 +2,6 @@ version 0.9.4
=============
- new VM:
- implement opcConv
- implement missing magics
- implement overflow checking
- implement the glue to replace evals.nim