new VM: register allocator bugfix; implemented more magics

This commit is contained in:
Araq 2013-08-08 21:10:54 +02:00
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, strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
parser, vmdeps, idents parser, vmdeps, idents
from semfold import leValueConv from semfold import leValueConv, ordinalValToString
type type
PStackFrame* = ref TStackFrame PStackFrame* = ref TStackFrame
@ -60,6 +60,12 @@ when not defined(nimHasInterpreterLoop):
template inc(pc: ptr TInstr, diff = 1) = template inc(pc: ptr TInstr, diff = 1) =
inc cast[TAddress](pc), TInstr.sizeof * diff 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.} = template ensureKind(k: expr) {.immediate, dirty.} =
if regs[ra].kind != k: if regs[ra].kind != k:
myreset(regs[ra]) myreset(regs[ra])
@ -170,6 +176,57 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
return pc return pc
return -1 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 = proc compile(c: PCtx, s: PSym): int =
result = vmgen.genProc(c, s) result = vmgen.genProc(c, s)
#c.echoCode #c.echoCode
@ -243,6 +300,7 @@ proc execute(c: PCtx, start: int) =
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
# XXX this creates a wrong alias # XXX this creates a wrong alias
#Message(c.debug[pc], warnUser, $regs[rb].len & " " & $rc)
asgnComplex(regs[ra], regs[rb].sons[rc]) asgnComplex(regs[ra], regs[rb].sons[rc])
of opcWrObj: of opcWrObj:
# a.b = c # a.b = c
@ -380,8 +438,9 @@ proc execute(c: PCtx, start: int) =
regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal) regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
of opcEqRef: of opcEqRef:
decodeBC(nkIntLit) decodeBC(nkIntLit)
regs[ra].intVal = ord(regs[rb] == regs[rc]) regs[ra].intVal = ord((regs[rb].kind == nkNilLit and
# XXX is this correct? nope ... regs[rc].kind == nkNilLit) or
regs[rb].sons == regs[rc].sons)
of opcXor: of opcXor:
decodeBC(nkIntLit) decodeBC(nkIntLit)
regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal) regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
@ -448,7 +507,11 @@ proc execute(c: PCtx, start: int) =
decodeB(nkBracket) decodeB(nkBracket)
regs[ra].add(copyTree(regs[rb])) regs[ra].add(copyTree(regs[rb]))
of opcEcho: 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: of opcContainsSet:
decodeBC(nkIntLit) decodeBC(nkIntLit)
regs[ra].intVal = Ord(inSet(regs[rb], regs[rc])) regs[ra].intVal = Ord(inSet(regs[rb], regs[rc]))
@ -691,7 +754,62 @@ proc execute(c: PCtx, start: int) =
let rb = instr.regB let rb = instr.regB
inc pc inc pc
let typ = c.types[c.code[pc].regBx - wordExcess] 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: else:
InternalError(c.debug[pc], "unknown opcode " & $instr.opcode) InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
inc pc inc pc

View file

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

View file

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

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

View file

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