summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-08-08 21:10:54 +0200
committerAraq <rumpf_a@web.de>2013-08-08 21:10:54 +0200
commit288cd05f89009b7432a0e95fec0b1cf78c4ea7e5 (patch)
tree7bbf312e7cd93fd1761bc9c79e5702c4e4e6e37c /compiler
parent06b3852143b2f3857da0090b9c18ac63812ec3cc (diff)
downloadNim-288cd05f89009b7432a0e95fec0b1cf78c4ea7e5.tar.gz
new VM: register allocator bugfix; implemented more magics
Diffstat (limited to 'compiler')
-rw-r--r--compiler/vm.nim128
-rw-r--r--compiler/vmdef.nim4
-rw-r--r--compiler/vmdeps.nim31
-rw-r--r--compiler/vmgen.nim95
4 files changed, 195 insertions, 63 deletions
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.. <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