summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2014-07-08 02:02:58 +0200
committerAraq <rumpf_a@web.de>2014-07-08 02:02:58 +0200
commitf16449ec22751ca0e864d70424760e540a80c804 (patch)
treea6dc81d9b0ae81d925345e64b4d32ec611ac8d22
parentf9d7e8db2a8b89575df51768ce9e5aa66c47cc9f (diff)
downloadNim-f16449ec22751ca0e864d70424760e540a80c804.tar.gz
fixes #1103; fixes #1297
-rw-r--r--compiler/vm.nim17
-rw-r--r--compiler/vmgen.nim82
-rw-r--r--tests/casestmt/tcase_arrayconstr.nim19
-rw-r--r--tests/macros/tbug1149.nim46
-rw-r--r--todo.txt4
5 files changed, 137 insertions, 31 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 7f5e0d1c5..f879e36bc 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -438,7 +438,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       if regs[rc].intVal > high(int):
         stackTrace(c, tos, pc, errIndexOutOfBounds)
       let idx = regs[rc].intVal.int
-      # XXX what if the array is not 0-based? -> codegen should insert a sub
       let src = regs[rb].node
       if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
         regs[ra].node = src.sons[idx]
@@ -504,13 +503,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       else:
         stackTrace(c, tos, pc, errNilAccess)
     of opcWrDeref:
-      # a[] = b
+      # a[] = c; b unused
       let ra = instr.regA
-      let rb = instr.regB
+      let rc = instr.regC
       case regs[ra].kind
-      of rkNodeAddr: putIntoNode(regs[ra].nodeAddr[], regs[rb])
-      of rkRegisterAddr: regs[ra].regAddr[] = regs[rb]
-      of rkNode: putIntoNode(regs[ra].node, regs[rb])
+      of rkNodeAddr: putIntoNode(regs[ra].nodeAddr[], regs[rc])
+      of rkRegisterAddr: regs[ra].regAddr[] = regs[rc]
+      of rkNode: putIntoNode(regs[ra].node, regs[rc])
       else: stackTrace(c, tos, pc, errNilAccess)
     of opcAddInt:
       decodeBC(rkInt)
@@ -751,11 +750,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         regs[ra].node.strVal.add getstr(regs[i])
     of opcAddStrCh:
       decodeB(rkNode)
-      createStrKeepNode regs[ra]
+      #createStrKeepNode regs[ra]
       regs[ra].node.strVal.add(regs[rb].intVal.chr)
     of opcAddStrStr:
       decodeB(rkNode)
-      createStrKeepNode regs[ra]
+      #createStrKeepNode regs[ra]
       regs[ra].node.strVal.add(regs[rb].node.strVal)
     of opcAddSeqElem:
       decodeB(rkNode)
@@ -992,7 +991,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         return TFullReg(kind: rkNone)
     of opcSetLenStr:
       decodeB(rkNode)
-      createStrKeepNode regs[ra]
+      #createStrKeepNode regs[ra]
       regs[ra].node.strVal.setLen(regs[rb].intVal.int)
     of opcOf:
       decodeBC(rkInt)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 28e0a8fd6..b04e60549 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -19,7 +19,13 @@
 # .. code-block:: nimrod
 #   let s = a & b  # no matter what, create fresh node
 #   s = a & b  # no matter what, keep the node
-#   
+#
+# Also *stores* into non-temporary memory need to perform deep copies:
+# a.b = x.y
+# We used to generate opcAsgn for the *load* of 'x.y' but this is clearly
+# wrong! We need to produce opcAsgn (the copy) for the *store*. This also
+# solves the opcLdConst vs opcAsgnConst issue. Of course whether we need
+# this copy depends on the involved types.
 
 import
   unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef, 
@@ -531,12 +537,12 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
     c.freeTemp(dest)
   of nkDerefExpr, nkHiddenDeref:
     let dest = c.genx(le.sons[0], {gfAddrOf})
-    c.gABC(le, opcWrDeref, dest, value)
+    c.gABC(le, opcWrDeref, dest, 0, value)
     c.freeTemp(dest)
   of nkSym:
     if le.sym.isGlobal:
       let dest = c.genx(le, {gfAddrOf})
-      c.gABC(le, opcWrDeref, dest, value)
+      c.gABC(le, opcWrDeref, dest, 0, value)
       c.freeTemp(dest)
   else:
     discard
@@ -1097,6 +1103,25 @@ proc checkCanEval(c: PCtx; n: PNode) =
         not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
       cannotEval(n)
 
+proc isTemp(c: PCtx; dest: TDest): bool =
+  result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
+
+template needsAdditionalCopy(n): expr =
+  not c.isTemp(dest) and not fitsRegister(n.typ)
+
+proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
+                       dest, idx, value: TRegister) =
+  # opcLdObj et al really means "load address". We sometimes have to create a
+  # copy in order to not introduce false aliasing:
+  # mylocal = a.b  # needs a copy of the data!
+  if needsAdditionalCopy(n):
+    var cc = c.getTemp(n.typ)
+    c.gABC(n, whichAsgnOpc(n), cc, value)
+    c.gABC(n, opc, dest, idx, cc)
+    c.freeTemp(cc)
+  else:
+    c.gABC(n, opc, dest, idx, value)
+
 proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   case le.kind
   of nkBracketExpr:
@@ -1105,9 +1130,9 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
     let tmp = c.genx(ri)
     if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
         tyString, tyCString}:
-      c.gABC(le, opcWrStrIdx, dest, idx, tmp)
+      c.preventFalseAlias(le, opcWrStrIdx, dest, idx, tmp)
     else:
-      c.gABC(le, opcWrArr, dest, idx, tmp)
+      c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
     c.freeTemp(tmp)
   of nkDotExpr, nkCheckedFieldExpr:
     # XXX field checks here
@@ -1115,12 +1140,12 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
     let dest = c.genx(left.sons[0], {gfAddrOf})
     let idx = genField(left.sons[1])
     let tmp = c.genx(ri)
-    c.gABC(left, opcWrObj, dest, idx, tmp)
+    c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
     c.freeTemp(tmp)
   of nkDerefExpr, nkHiddenDeref:
     let dest = c.genx(le.sons[0], {gfAddrOf})
     let tmp = c.genx(ri)
-    c.gABC(le, opcWrDeref, dest, tmp)
+    c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
     c.freeTemp(tmp)
   of nkSym:
     let s = le.sym
@@ -1129,24 +1154,32 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
       withTemp(tmp, le.typ):
         c.gen(le, tmp, {gfAddrOf})
         let val = c.genx(ri)
-        c.gABC(le, opcWrDeref, tmp, val)
+        c.preventFalseAlias(le, opcWrDeref, tmp, 0, val)
         c.freeTemp(val)
     else:
       if s.kind == skForVar: c.setSlot s
       internalAssert s.position > 0 or (s.position == 0 and
                                         s.kind in {skParam,skResult})
       var dest: TRegister = s.position + ord(s.kind == skParam)
-      gen(c, ri, dest)
+      if needsAdditionalCopy(le) and s.kind in {skResult, skVar, skParam}:
+        var cc = c.getTemp(le.typ)
+        gen(c, ri, cc)
+        c.gABC(le, whichAsgnOpc(le), dest, cc)
+        c.freeTemp(cc)
+      else:
+        gen(c, ri, dest)
   else:
     let dest = c.genx(le, {gfAddrOf})
     genAsgn(c, dest, ri, requiresCopy)
 
 proc genLit(c: PCtx; n: PNode; dest: var TDest) =
-  var opc = opcLdConst
+  # opcLdConst is now always valid. We produce the necessary copy in the
+  # assignments now:
+  #var opc = opcLdConst
   if dest < 0: dest = c.getTemp(n.typ)
-  elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
+  #elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
   let lit = genLiteral(c, n)
-  c.gABx(n, opc, dest, lit)
+  c.gABx(n, opcLdConst, dest, lit)
 
 proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
   var n = newNode(nkType)
@@ -1175,7 +1208,7 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
   let dest = c.getTemp(s.typ)
   c.gABx(n, opcLdGlobal, dest, s.position)
   let tmp = c.genx(s.ast)
-  c.gABC(n, opcWrDeref, dest, tmp)
+  c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
   c.freeTemp(dest)
   c.freeTemp(tmp)
 
@@ -1332,7 +1365,7 @@ proc genVarSection(c: PCtx; n: PNode) =
         if a.sons[2].kind != nkEmpty:
           let tmp = c.genx(a.sons[0], {gfAddrOf})
           let val = c.genx(a.sons[2])
-          c.gABC(a, opcWrDeref, tmp, val)
+          c.preventFalseAlias(a, opcWrDeref, tmp, 0, val)
           c.freeTemp(val)
           c.freeTemp(tmp)
       else:
@@ -1342,7 +1375,14 @@ proc genVarSection(c: PCtx; n: PNode) =
         else:
           if not fitsRegister(s.typ):
             c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
-          gen(c, a.sons[2], s.position.TRegister)
+          let le = a.sons[0]
+          if not fitsRegister(le.typ) and s.kind in {skResult, skVar, skParam}:
+            var cc = c.getTemp(le.typ)
+            gen(c, a.sons[2], cc)
+            c.gABC(le, whichAsgnOpc(le), s.position.TRegister, cc)
+            c.freeTemp(cc)
+          else:
+            gen(c, a.sons[2], s.position.TRegister)
     else:
       # assign to a.sons[0]; happens for closures
       if a.sons[2].kind == nkEmpty:
@@ -1370,7 +1410,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
     c.gABx(n, opcLdNullReg, tmp, c.genType(intType))
     for x in n:
       let a = c.genx(x)
-      c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
+      c.preventFalseAlias(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
       c.gABI(n, opcAddImmInt, tmp, tmp, 1)
       c.freeTemp(a)
     c.freeTemp(tmp)
@@ -1402,7 +1442,8 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
     if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
       let idx = genField(it.sons[0])
       let tmp = c.genx(it.sons[1])
-      c.gABC(it, whichAsgnOpc(it.sons[1], opcWrObj), dest, idx, tmp)
+      c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
+                          dest, idx, tmp)
       c.freeTemp(tmp)
     else:
       internalError(n.info, "invalid object constructor")
@@ -1416,11 +1457,12 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
     if it.kind == nkExprColonExpr:
       let idx = genField(it.sons[0])
       let tmp = c.genx(it.sons[1])
-      c.gABC(it, whichAsgnOpc(it.sons[1], opcWrObj), dest, idx, tmp)
+      c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
+                          dest, idx, tmp)
       c.freeTemp(tmp)
     else:
       let tmp = c.genx(it)
-      c.gABC(it, whichAsgnOpc(it, opcWrObj), dest, i.TRegister, tmp)
+      c.preventFalseAlias(it, whichAsgnOpc(it, opcWrObj), dest, i.TRegister, tmp)
       c.freeTemp(tmp)
 
 proc genProc*(c: PCtx; s: PSym): int
@@ -1658,7 +1700,7 @@ proc genProc(c: PCtx; s: PSym): int =
     c.gABC(body, opcEof, eofInstr.regA)
     c.optimizeJumps(result)
     s.offset = c.prc.maxSlots
-    #if s.name.s == "find":
+    #if s.name.s == "get_data":
     #  echo renderTree(body)
     #  c.echoCode(result)
     c.prc = oldPrc
diff --git a/tests/casestmt/tcase_arrayconstr.nim b/tests/casestmt/tcase_arrayconstr.nim
new file mode 100644
index 000000000..cd7156600
--- /dev/null
+++ b/tests/casestmt/tcase_arrayconstr.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''Not found!
+Found!'''
+"""
+
+const
+  md_extension = [".md", ".markdown"]
+
+proc test(ext: string) =
+  case ext
+  of ".txt", md_extension:
+    echo "Found!"
+  else:
+    echo "Not found!"
+
+test(".something")
+# ensure it's not evaluated at compile-time:
+var foo = ".markdown"
+test(foo)
diff --git a/tests/macros/tbug1149.nim b/tests/macros/tbug1149.nim
index 5c4cb8530..d2bff61d3 100644
--- a/tests/macros/tbug1149.nim
+++ b/tests/macros/tbug1149.nim
@@ -2,7 +2,13 @@ discard """
 msg: '''a
 s
 d
-f'''
+f
+TTaa
+TTaa
+TTaa
+TTaa'''
+
+output: '''test'''
 """
 
 type
@@ -18,3 +24,41 @@ macro test(): stmt =
     echo i.s
 
 test()
+
+
+# bug 1297
+
+import macros
+
+type TType = tuple[s: string]
+
+macro echotest(): stmt =
+  var t: TType
+  t.s = ""
+  t.s.add("test")
+  result = newCall(newIdentNode("echo"), newStrLitNode(t.s))
+
+echotest()
+
+# bug #1103
+
+type 
+    Td = tuple
+        a:string
+        b:int
+
+proc get_data(d: Td) : string {.compileTime.} =
+    result = d.a # Works if a literal string is used here. 
+    # Bugs if line A or B is active. Works with C
+    result &= "aa"          # A
+    #result.add("aa")       # B
+    #result = result & "aa" # C
+
+macro m(s:static[Td]) : stmt =
+    echo get_data(s)
+    echo get_data(s)
+    result = newEmptyNode()
+
+const s=("TT", 3)
+m(s)
+m(s)
diff --git a/todo.txt b/todo.txt
index f027be8d5..8a1caee3b 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,7 +1,8 @@
 version 0.9.6
 =============
 
-- some table related tests are wrong (memory usage checks)
+- integrate the new LL into the devel branch
+- start experimental branch
 
 Concurrency
 -----------
@@ -31,6 +32,7 @@ Misc
 - type API for macros; make 'spawn' a macro
 - markAndSweepGC should expose an API for fibers
 - prevent 'alloc(TypeWithGCedMemory)'
+- some table related tests are wrong (memory usage checks)
 
 
 Bugs