diff options
-rw-r--r-- | compiler/dfa.nim | 100 | ||||
-rw-r--r-- | compiler/injectdestructors.nim | 4 | ||||
-rw-r--r-- | tests/arc/tmovebug.nim | 31 |
3 files changed, 106 insertions, 29 deletions
diff --git a/compiler/dfa.nim b/compiler/dfa.nim index efd826594..f3985822b 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -574,32 +574,84 @@ proc skipConvDfa*(n: PNode): PNode = result = result[1] else: break -proc aliases*(obj, field: PNode): bool = - var n = field - var obj = obj - while true: - case obj.kind - of {nkObjDownConv, nkObjUpConv, nkAddr, nkHiddenAddr, nkDerefExpr, nkHiddenDeref}: - obj = obj[0] - of PathKinds1: - obj = obj[1] - else: break - while true: - if sameTrees(obj, n): return true - case n.kind - of PathKinds0: - n = n[0] - of PathKinds1: - n = n[1] - else: break +type AliasKind* = enum + yes, no, maybe + +proc aliases*(obj, field: PNode): AliasKind = + # obj -> field: + # x -> x: true + # x -> x.f: true + # x.f -> x: false + # x.f -> x.f: true + # x.f -> x.v: false + # x -> x[0]: true + # x[0] -> x: false + # x[0] -> x[0]: true + # x[0] -> x[1]: false + # x -> x[i]: true + # x[i] -> x: false + # x[i] -> x[i]: maybe; Further analysis could make this return true when i is a runtime-constant + # x[i] -> x[j]: maybe; also returns maybe if only one of i or j is a compiletime-constant + template collectImportantNodes(result, n) = + var result: seq[PNode] + var n = n + while true: + case n.kind + of PathKinds0 - {nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}: + n = n[0] + of PathKinds1: + n = n[1] + of nkDotExpr, nkCheckedFieldExpr, nkBracketExpr: + result.add n + n = n[0] + of nkSym: + result.add n; break + else: return no + + collectImportantNodes(objImportantNodes, obj) + collectImportantNodes(fieldImportantNodes, field) + + # If field is less nested than obj, then it cannot be part of/aliased by obj + if fieldImportantNodes.len < objImportantNodes.len: return no + + result = yes + for i in 1..objImportantNodes.len: + # We compare the nodes leading to the location of obj and field + # with each other. + # We continue until they diverge, in which case we return no, or + # until we reach the location of obj, in which case we do not need + # to look further, since field must be part of/aliased by obj now. + # If we encounter an element access using an index which is a runtime value, + # we simply return maybe instead of yes; should further nodes not diverge. + let currFieldPath = fieldImportantNodes[^i] + let currObjPath = objImportantNodes[^i] + + if currFieldPath.kind != currObjPath.kind: + return no + + case currFieldPath.kind + of nkSym: + if currFieldPath.sym != currObjPath.sym: return no + of nkDotExpr, nkCheckedFieldExpr: + if currFieldPath[1].sym != currObjPath[1].sym: return no + of nkBracketExpr: + if currFieldPath[1].kind in nkLiterals and currObjPath[1].kind in nkLiterals: + if currFieldPath[1].intVal != currObjPath[1].intVal: + return no + else: + result = maybe + else: assert false # unreachable type InstrTargetKind* = enum None, Full, Partial proc instrTargets*(insloc, loc: PNode): InstrTargetKind = - if sameTrees(insloc, loc) or insloc.aliases(loc): + case insloc.aliases(loc) + of yes: Full # x -> x; x -> x.f - elif loc.aliases(insloc): + of maybe: + Partial # We treat this like a partial write/read + elif loc.aliases(insloc) != no: Partial # x.f -> x else: None @@ -607,16 +659,10 @@ proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = var n = orig while true: case n.kind - of PathKinds0 - {nkBracketExpr, nkHiddenDeref, nkDerefExpr}: + of PathKinds0 - {nkHiddenDeref, nkDerefExpr}: n = n[0] of PathKinds1: n = n[1] - of nkBracketExpr: - # in a[i] the 'i' must be known - if n.len > 1 and n[1].kind in {nkCharLit..nkUInt64Lit}: - n = n[0] - else: - return false of nkHiddenDeref, nkDerefExpr: # We "own" sinkparam[].loc but not ourVar[].location as it is a nasty # pointer indirection. diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index cb9547bf2..3069d742c 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -969,7 +969,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = proc sameLocation*(a, b: PNode): bool = proc sameConstant(a, b: PNode): bool = - a.kind in nkLiterals and exprStructuralEquivalent(a, b) + a.kind in nkLiterals and a.intVal == b.intVal const nkEndPoint = {nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr} if a.kind in nkEndPoint and b.kind in nkEndPoint: @@ -1006,7 +1006,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod # unpacking of tuple: take over the elements result = c.genSink(dest, p(ri, c, s, consumed), isDecl) elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c): - if not aliases(dest, ri): + if aliases(dest, ri) == no: # Rule 3: `=sink`(x, z); wasMoved(z) var snk = c.genSink(dest, ri, isDecl) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 71962e21d..7c8fbc235 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -92,10 +92,20 @@ copy destroy destroy destroy +sink +sink +destroy +copy +(f: 1) +destroy +destroy part-to-whole assigment: sink (children: @[]) destroy +sink +(children: @[]) +destroy copy destroy ''' @@ -675,6 +685,16 @@ proc caseNotAConstant = caseNotAConstant() +proc potentialSelfAssign(i: var int) = + var a: array[2, OO] + a[i] = OO(f: 1) + a[1] = OO(f: 2) + a[i+1] = a[i] # This must not =sink, but =copy + inc i + echo a[i-1] # (f: 1) + +potentialSelfAssign (var xi = 0; xi) + #-------------------------------------------------------------------- echo "part-to-whole assigment:" @@ -700,6 +720,17 @@ proc partToWholeSeq = partToWholeSeq() +proc partToWholeSeqRTIndex = + var i = 0 + var t = Tree(children: @[Tree()]) + t = t.children[i] # See comment in partToWholeSeq + + var tc = TreeDefaultHooks(children: @[TreeDefaultHooks()]) + tc = tc.children[i] # See comment in partToWholeSeq + echo tc + +partToWholeSeqRTIndex() + type List = object next: ref List |