mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-30 09:54:49 +00:00
new VM: register allocator bugfix; implemented more magics
This commit is contained in:
128
compiler/vm.nim
128
compiler/vm.nim
@@ -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
|
||||
|
||||
@@ -78,6 +78,10 @@ type
|
||||
opcNGetType,
|
||||
opcNStrVal,
|
||||
|
||||
opcNSetIntVal,
|
||||
opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
|
||||
opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree,
|
||||
|
||||
opcSlurp,
|
||||
opcGorge,
|
||||
opcParseExprToAst,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user