From 288cd05f89009b7432a0e95fec0b1cf78c4ea7e5 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 8 Aug 2013 21:10:54 +0200 Subject: new VM: register allocator bugfix; implemented more magics --- compiler/vm.nim | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++-- compiler/vmdef.nim | 4 ++ compiler/vmdeps.nim | 31 +------------ compiler/vmgen.nim | 95 ++++++++++++++++++++++++++------------ 4 files changed, 195 insertions(+), 63 deletions(-) (limited to 'compiler') diff --git a/compiler/vm.nim b/compiler/vm.nim index 86d1fbe07..d09d57d89 100644 --- a/compiler/vm.nim +++ b/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 diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 90d23e642..a76e035a0 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -78,6 +78,10 @@ type opcNGetType, opcNStrVal, + opcNSetIntVal, + opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal, + opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, + opcSlurp, opcGorge, opcParseExprToAst, diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 7a645aca9..919cd5f9d 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -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 diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 2033fb23c..016cfc96c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -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..