summary refs log tree commit diff stats
path: root/compiler/dfa.nim
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2019-04-15 17:57:59 +0200
committerAraq <rumpf_a@web.de>2019-04-16 10:35:43 +0200
commit045e026d0ee4e6decc4f22f1f9cbb0bdd8bc3b45 (patch)
tree50b70427b53bc39ce6df075eaccbfebd74663122 /compiler/dfa.nim
parent01f09567c43031d3d35a54c8856d79f6cd1d4bf7 (diff)
downloadNim-045e026d0ee4e6decc4f22f1f9cbb0bdd8bc3b45.tar.gz
dfa.nim: track object/tuple field accesses more precisely; sink(o.x); sink(o.y) needs to compile; activate the tuple unpacking transf.nim bugfix
Diffstat (limited to 'compiler/dfa.nim')
-rw-r--r--compiler/dfa.nim73
1 files changed, 56 insertions, 17 deletions
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 2b5cd350a..cdb912163 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -29,7 +29,10 @@
 ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen.
 ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
 
-import ast, astalgo, types, intsets, tables, msgs, options, lineinfos
+import ast, astalgo, types, intsets, tables, msgs, options, lineinfos, renderer
+
+from patterns import sameTrees
+from aliases import isPartOf, TAnalysisResult
 
 type
   InstrKind* = enum
@@ -37,7 +40,10 @@ type
   Instr* = object
     n*: PNode
     case kind*: InstrKind
-    of def, use: sym*: PSym
+    of def, use: sym*: PSym # 'sym' can also be 'nil' and
+                            # then 'n' contains the def/use location.
+                            # This is used so that we can track object
+                            # and tuple field accesses precisely.
     of goto, fork, join: dest*: int
 
   ControlFlowGraph* = seq[Instr]
@@ -47,9 +53,6 @@ type
     label: PSym
     fixups: seq[TPosition]
 
-  ValueKind = enum
-    undef, value, valueOrUndef
-
   Con = object
     code: ControlFlowGraph
     inCall, inTryStmt: int
@@ -77,7 +80,7 @@ proc codeListing(c: ControlFlowGraph, result: var string, start=0; last = -1) =
     result.add "\t"
     case c[i].kind
     of def, use:
-      result.add c[i].sym.name.s
+      result.add renderTree(c[i].n)
     of goto, fork, join:
       result.add "L"
       result.add c[i].dest+i
@@ -564,16 +567,50 @@ proc genReturn(c: var Con; n: PNode) =
   genNoReturn(c, n)
 
 const
-  InterestingSyms = {skVar, skResult, skLet, skParam, skForVar}
-
-proc genUse(c: var Con; n: PNode) =
-  var n = n
-  while n.kind in {nkDotExpr, nkCheckedFieldExpr,
-                   nkBracketExpr, nkDerefExpr, nkHiddenDeref,
-                   nkAddr, nkHiddenAddr}:
+  InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp}
+  PathKinds* = {nkDotExpr, nkCheckedFieldExpr,
+                nkBracketExpr, nkDerefExpr, nkHiddenDeref,
+                nkAddr, nkHiddenAddr}
+
+proc genUse(c: var Con; orig: PNode) =
+  var n = orig
+  var iters = 0
+  while n.kind in PathKinds:
     n = n[0]
+    inc iters
   if n.kind == nkSym and n.sym.kind in InterestingSyms:
-    c.code.add Instr(n: n, kind: use, sym: n.sym)
+    c.code.add Instr(n: orig, kind: use, sym: if iters > 0: nil else: n.sym)
+
+proc instrTargets*(ins: Instr; loc: PNode): bool =
+  assert ins.kind in {def, use}
+  if ins.sym != nil and loc.kind == nkSym:
+    result = ins.sym == loc.sym
+  else:
+    result = ins.n == loc or sameTrees(ins.n, loc)
+  if not result:
+    # We can come here if loc is 'x.f' and ins.n is 'x' or the other way round.
+    # def x.f; question: does it affect the full 'x'? No.
+    # def x; question: does it affect the 'x.f'? Yes.
+    # use x.f;  question: does it affect the full 'x'? No.
+    # use x; question does it affect 'x.f'? Yes.
+    result = isPartOf(ins.n, loc) == arYes
+
+proc isAnalysableFieldAccess*(n: PNode; owner: PSym): bool =
+  var n = n
+  while true:
+    if n.kind in {nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv, nkObjDownConv, nkObjUpConv}:
+      n = n[0]
+    elif n.kind == nkBracketExpr:
+      let x = n[0]
+      if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
+        n = x
+      else:
+        break
+    else:
+      break
+  # XXX Allow closure deref operations here if we know
+  # the owner controlled the closure allocation?
+  result = n.kind == nkSym and n.sym.owner == owner and owner.kind != skModule
 
 proc genDef(c: var Con; n: PNode) =
   if n.kind == nkSym and n.sym.kind in InterestingSyms:
@@ -651,10 +688,12 @@ proc gen(c: var Con; n: PNode) =
   of nkCharLit..nkNilLit: discard
   of nkAsgn, nkFastAsgn:
     gen(c, n[1])
+    # watch out: 'obj[i].f2 = value' sets 'f2' but
+    # "uses" 'i'. But we are only talking about builtin array indexing so
+    # it doesn't matter and 'x = 34' is NOT a usage of 'x'.
     genDef(c, n[0])
-  of nkDotExpr, nkCheckedFieldExpr, nkBracketExpr,
-     nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr:
-    gen(c, n[0])
+  of PathKinds:
+    genUse(c, n)
   of nkIfStmt, nkIfExpr: genIf(c, n)
   of nkWhenStmt:
     # This is "when nimvm" node. Chose the first branch.