summary refs log tree commit diff stats
path: root/compiler/injectdestructors.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/injectdestructors.nim')
-rw-r--r--compiler/injectdestructors.nim62
1 files changed, 42 insertions, 20 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 606e46568..846dcdf5d 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -82,7 +82,7 @@ proc aliasesCached(cache: var AliasCache, obj, field: PNode): AliasKind =
     cache[key] = aliases(obj, field)
   cache[key]
 
-proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, alreadySeen: var HashSet[PNode], lastReads, potLastReads: var IntSet; pc: var int, until: int) =
+proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, lastReads, potLastReads: var IntSet; pc: var int, until: int) =
   template aliasesCached(obj, field: PNode): untyped =
     aliasesCached(cache, obj, field)
   while pc < until:
@@ -100,15 +100,6 @@ proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, alreadySeen:
           cfg[r].n.comment = '\n' & $pc
           potLastReads.excl r
 
-      var alreadySeenThisNode = false
-      for s in alreadySeen:
-        if cfg[pc].n.aliases(s) != no or s.aliases(cfg[pc].n) != no:
-          alreadySeenThisNode = true; break
-      if alreadySeenThisNode: cfg[pc].n.flags.excl nfFirstWrite
-      else: cfg[pc].n.flags.incl nfFirstWrite
-
-      alreadySeen.incl cfg[pc].n
-
       inc pc
     of use:
       let potLastReadsCopy = potLastReads
@@ -119,25 +110,19 @@ proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, alreadySeen:
 
       potLastReads.incl pc
 
-      alreadySeen.incl cfg[pc].n
-
       inc pc
     of goto:
       pc += cfg[pc].dest
     of fork:
-      # every branch must lead to the last read of the location:
       var variantA = pc + 1
       var variantB = pc + cfg[pc].dest
       var potLastReadsA, potLastReadsB = potLastReads
       var lastReadsA, lastReadsB: IntSet
-      var alreadySeenA, alreadySeenB = alreadySeen
       while variantA != variantB and max(variantA, variantB) < cfg.len and min(variantA, variantB) < until:
         if variantA < variantB:
-          collectLastReads(cfg, cache, alreadySeenA, lastReadsA, potLastReadsA, variantA, min(variantB, until))
+          collectLastReads(cfg, cache, lastReadsA, potLastReadsA, variantA, min(variantB, until))
         else:
-          collectLastReads(cfg, cache, alreadySeenB, lastReadsB, potLastReadsB, variantB, min(variantA, until))
-
-      alreadySeen.incl alreadySeenA + alreadySeenB
+          collectLastReads(cfg, cache, lastReadsB, potLastReadsB, variantB, min(variantA, until))
 
       # Add those last reads that were turned into last reads on both branches
       lastReads.incl lastReadsA * lastReadsB
@@ -157,6 +142,40 @@ proc collectLastReads(cfg: ControlFlowGraph; cache: var AliasCache, alreadySeen:
 
       pc = min(variantA, variantB)
 
+proc collectFirstWrites(cfg: ControlFlowGraph; alreadySeen: var HashSet[PNode]; pc: var int, until: int) =
+  while pc < until:
+    case cfg[pc].kind
+    of def:
+      var alreadySeenThisNode = false
+      for s in alreadySeen:
+        if cfg[pc].n.aliases(s) != no or s.aliases(cfg[pc].n) != no:
+          alreadySeenThisNode = true; break
+      if alreadySeenThisNode: cfg[pc].n.flags.excl nfFirstWrite
+      else: cfg[pc].n.flags.incl nfFirstWrite
+
+      alreadySeen.incl cfg[pc].n
+
+      inc pc
+    of use:
+      alreadySeen.incl cfg[pc].n
+
+      inc pc
+    of goto:
+      pc += cfg[pc].dest
+    of fork:
+      var variantA = pc + 1
+      var variantB = pc + cfg[pc].dest
+      var alreadySeenA, alreadySeenB = alreadySeen
+      while variantA != variantB and max(variantA, variantB) < cfg.len and min(variantA, variantB) < until:
+        if variantA < variantB:
+          collectFirstWrites(cfg, alreadySeenA, variantA, min(variantB, until))
+        else:
+          collectFirstWrites(cfg, alreadySeenB, variantB, min(variantA, until))
+
+      alreadySeen.incl alreadySeenA + alreadySeenB
+
+      pc = min(variantA, variantB)
+
 proc isLastRead(n: PNode; c: var Con): bool =
   let m = dfa.skipConvDfa(n)
   (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or nfLastRead in m.flags
@@ -1086,10 +1105,9 @@ proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n:
 
   block:
     var cache = initTable[(PNode, PNode), AliasKind]()
-    var alreadySeen: HashSet[PNode]
     var lastReads, potLastReads: IntSet
     var pc = 0
-    collectLastReads(c.g, cache, alreadySeen, lastReads, potLastReads, pc, c.g.len)
+    collectLastReads(c.g, cache, lastReads, potLastReads, pc, c.g.len)
     lastReads.incl potLastReads
     var lastReadTable: Table[PNode, seq[int]]
     for position, node in c.g:
@@ -1102,6 +1120,10 @@ proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n:
       if allPositionsLastRead:
         node.flags.incl nfLastRead
 
+    var alreadySeen: HashSet[PNode]
+    pc = 0
+    collectFirstWrites(c.g, alreadySeen, pc, c.g.len)
+
   var scope: Scope
   let body = p(n, c, scope, normal)