summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2019-01-21 19:46:06 +0100
committerAndreas Rumpf <rumpf_a@web.de>2019-01-23 11:08:51 +0100
commit1b0372c6e9d316d64770c2384bd29caf8e6e60c9 (patch)
tree8259df13c7f61d80a3625990bcbd7214b87fcf3b
parent11022fea1b530aceced4c3f24d9295898d2eaf44 (diff)
downloadNim-1b0372c6e9d316d64770c2384bd29caf8e6e60c9.tar.gz
make tests green again
-rw-r--r--compiler/destroyer.nim131
1 files changed, 81 insertions, 50 deletions
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index ca2aa8558..1881730e8 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -188,6 +188,35 @@ proc isHarmlessVar*(s: PSym; c: Con): bool =
       discard "we do not perform an abstract interpretation yet"
   result = usages <= 1
 
+proc isLastRead(s: PSym; c: var Con; pc, comesFrom: int): int =
+  var pc = pc
+  while pc < c.g.len:
+    case c.g[pc].kind
+    of def:
+      if c.g[pc].sym == s:
+        # the path lead to a redefinition of 's' --> abandon it.
+        return pc
+      inc pc
+    of use:
+      if c.g[pc].sym == s:
+        c.otherRead = c.g[pc].n
+        return -1
+      inc pc
+    of goto:
+      pc = pc + c.g[pc].dest
+    of fork:
+      # every branch must lead to the last read of the location:
+      let variantA = isLastRead(s, c, pc+1, pc)
+      if variantA < 0: return -1
+      let variantB = isLastRead(s, c, pc + c.g[pc].dest, pc)
+      if variantB < 0: return -1
+      pc = variantA+1
+    of InstrKind.join:
+      let dest = pc + c.g[pc].dest
+      if dest == comesFrom: return pc
+      inc pc
+  return pc
+
 proc isLastRead(n: PNode; c: var Con): bool =
   # first we need to search for the instruction that belongs to 'n':
   doAssert n.kind == nkSym
@@ -195,61 +224,63 @@ proc isLastRead(n: PNode; c: var Con): bool =
   var instr = -1
   for i in 0..<c.g.len:
     if c.g[i].n == n:
-      if instr < 0: instr = i
-      else:
-        # eh, we found two positions that belong to 'n'?
-        # better return 'false' then:
-        return false
+      if instr < 0:
+        instr = i
+        break
+
   if instr < 0: return false
   # we go through all paths beginning from 'instr+1' and need to
   # ensure that we don't find another 'use X' instruction.
   if instr+1 >= c.g.len: return true
-  let s = n.sym
-  var pcs: seq[int] = @[instr+1]
-  var takenGotos: IntSet
-  var takenForks = initIntSet()
-  while pcs.len > 0:
-    var pc = pcs.pop
-
-    takenGotos = initIntSet()
-    while pc < c.g.len:
-      case c.g[pc].kind
-      of def:
-        if c.g[pc].sym == s:
-          # the path lead to a redefinition of 's' --> abandon it.
-          when false:
-            # Too complex thinking ahead: In reality it is enough to find
-            # the 'def x' here on the current path to make the 'use x' valid.
-            # but for this the definition needs to dominate the usage:
-            var dominates = true
-            for j in pc+1 .. instr:
-              # not within the same basic block?
-              if c.g[j].kind in {goto, fork} and (j + c.g[j].dest) in (pc+1 .. instr):
-                #if j in c.jumpTargets:
-                dominates = false
-            if dominates: break
-          break
-        inc pc
-      of use:
-        if c.g[pc].sym == s:
-          c.otherRead = c.g[pc].n
-          return false
-        inc pc
-      of goto:
-        # we must leave endless loops eventually:
-        if not takenGotos.containsOrIncl(pc):
-          pc = pc + c.g[pc].dest
-        else:
+  when false:
+    result = isLastRead(n.sym, c, 0, -1) >= 0
+  else:
+    let s = n.sym
+    var pcs: seq[int] = @[instr+1]
+    var takenGotos: IntSet
+    var takenForks = initIntSet()
+    while pcs.len > 0:
+      var pc = pcs.pop
+
+      takenGotos = initIntSet()
+      while pc < c.g.len:
+        case c.g[pc].kind
+        of def:
+          if c.g[pc].sym == s:
+            # the path lead to a redefinition of 's' --> abandon it.
+            when false:
+              # Too complex thinking ahead: In reality it is enough to find
+              # the 'def x' here on the current path to make the 'use x' valid.
+              # but for this the definition needs to dominate the usage:
+              var dominates = true
+              for j in pc+1 .. instr:
+                # not within the same basic block?
+                if c.g[j].kind in {goto, fork} and (j + c.g[j].dest) in (pc+1 .. instr):
+                  #if j in c.jumpTargets:
+                  dominates = false
+              if dominates: break
+            break
+          inc pc
+        of use:
+          if c.g[pc].sym == s:
+            c.otherRead = c.g[pc].n
+            return false
+          inc pc
+        of goto:
+          # we must leave endless loops eventually:
+          if not takenGotos.containsOrIncl(pc):
+            pc = pc + c.g[pc].dest
+          else:
+            inc pc
+        of fork:
+          # we follow the next instruction but push the dest onto our "work" stack:
+          if not takenForks.containsOrIncl(pc):
+            pcs.add pc + c.g[pc].dest
+          inc pc
+        of InstrKind.join:
           inc pc
-      of fork:
-        # we follow the next instruction but push the dest onto our "work" stack:
-        if not takenForks.containsOrIncl(pc):
-          pcs.add pc + c.g[pc].dest
-        inc pc
-      of InstrKind.join:
-        inc pc
-  #echo c.graph.config $ n.info, " last read here!"
-  return true
+    #echo c.graph.config $ n.info, " last read here!"
+    return true
 
 template interestingSym(s: PSym): bool =
   s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ)