diff options
author | Araq <rumpf_a@web.de> | 2019-04-15 17:57:59 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2019-04-16 10:35:43 +0200 |
commit | 045e026d0ee4e6decc4f22f1f9cbb0bdd8bc3b45 (patch) | |
tree | 50b70427b53bc39ce6df075eaccbfebd74663122 /compiler/dfa.nim | |
parent | 01f09567c43031d3d35a54c8856d79f6cd1d4bf7 (diff) | |
download | Nim-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.nim | 73 |
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. |