An optimizer for ARC (#14962)
* WIP: an optimizer for ARC * do not optimize away destructors in 'finally' if unstructured control flow is involved * optimized the optimizer * minor code cleanup * first steps to .cursor inference * cursor inference: big steps to a working solution * baby steps * better .cursor inference * new feature: expandArc for easy inspection of the AST after ARC transformations * added topt_cursor test * adapt tests * cleanups, make tests green * optimize common traversal patterns * moved test case * fixes .cursor inference so that npeg compiles once again * cursor inference: more bugfixes Co-authored-by: Clyybber <darkmine956@gmail.com>
This commit is contained in:
parent
813dd1b670
commit
c5358b0d4b
19 changed files with 895 additions and 62 deletions
|
|
@ -13,18 +13,11 @@
|
|||
|
||||
## See doc/destructors.rst for a spec of the implemented rewrite rules
|
||||
|
||||
## XXX Optimization to implement: if a local variable is only assigned
|
||||
## string literals as in ``let x = conf: "foo" else: "bar"`` do not
|
||||
## produce a destructor call for ``x``. The address of ``x`` must also
|
||||
## not have been taken. ``x = "abc"; x.add(...)``
|
||||
|
||||
# Todo:
|
||||
# - eliminate 'wasMoved(x); destroy(x)' pairs as a post processing step.
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents,
|
||||
intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents,
|
||||
strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
|
||||
lineinfos, parampatterns, sighashes, liftdestructors
|
||||
lineinfos, parampatterns, sighashes, liftdestructors, optimizer,
|
||||
cursor_inference
|
||||
|
||||
from trees import exprStructuralEquivalent, getRoot
|
||||
|
||||
|
|
@ -42,6 +35,7 @@ type
|
|||
Con = object
|
||||
owner: PSym
|
||||
g: ControlFlowGraph
|
||||
cursors: IntSet
|
||||
graph: ModuleGraph
|
||||
otherRead: PNode
|
||||
inLoop, inSpawn: int
|
||||
|
|
@ -155,6 +149,17 @@ proc isLastRead(location: PNode; cfg: ControlFlowGraph; otherRead: var PNode; pc
|
|||
pc = min(variantA, variantB)
|
||||
return pc
|
||||
|
||||
proc isCursor(n: PNode; c: Con): bool =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
result = sfCursor in n.sym.flags or c.cursors.contains(n.sym.id)
|
||||
of nkDotExpr:
|
||||
result = sfCursor in n[1].sym.flags
|
||||
of nkCheckedFieldExpr:
|
||||
result = isCursor(n[0], c)
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc isLastRead(n: PNode; c: var Con): bool =
|
||||
# first we need to search for the instruction that belongs to 'n':
|
||||
var instr = -1
|
||||
|
|
@ -486,17 +491,6 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode =
|
|||
else:
|
||||
result = arg
|
||||
|
||||
proc isCursor(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
result = sfCursor in n.sym.flags
|
||||
of nkDotExpr:
|
||||
result = sfCursor in n[1].sym.flags
|
||||
of nkCheckedFieldExpr:
|
||||
result = isCursor(n[0])
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc cycleCheck(n: PNode; c: var Con) =
|
||||
if c.graph.config.selectedGC != gcArc: return
|
||||
var value = n[1]
|
||||
|
|
@ -727,7 +721,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
|||
elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkNilLit} +
|
||||
nkCallKinds + nkLiterals:
|
||||
result = p(n, c, s, consumed)
|
||||
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and isLastRead(n, c):
|
||||
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
|
||||
isLastRead(n, c) and not (n.kind == nkSym and isCursor(n, c)):
|
||||
# Sinked params can be consumed only once. We need to reset the memory
|
||||
# to disable the destructor which we have not elided
|
||||
result = destructiveMoveVar(n, c, s)
|
||||
|
|
@ -830,7 +825,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
|||
if it.kind == nkVarTuple and hasDestructor(ri.typ):
|
||||
let x = lowerTupleUnpacking(c.graph, it, c.owner)
|
||||
result.add p(x, c, s, consumed)
|
||||
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isCursor(it[0]):
|
||||
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isCursor(it[0], c):
|
||||
for j in 0..<it.len-2:
|
||||
let v = it[j]
|
||||
if v.kind == nkSym:
|
||||
|
|
@ -851,7 +846,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
|||
result.add v
|
||||
of nkAsgn, nkFastAsgn:
|
||||
if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and
|
||||
not isCursor(n[0]):
|
||||
not isCursor(n[0], c):
|
||||
# rule (self-assignment-removal):
|
||||
if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
|
|
@ -988,7 +983,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod
|
|||
let snk = c.genSink(dest, ri, isDecl)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
|
||||
isLastRead(ri, c) and canBeMoved(c, dest.typ):
|
||||
isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri, c):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
let snk = c.genSink(dest, ri, isDecl)
|
||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||
|
|
@ -1048,6 +1043,8 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
|||
echoCfg(c.g)
|
||||
echo n
|
||||
|
||||
c.cursors = computeCursors(n, g.config)
|
||||
|
||||
var scope: Scope
|
||||
let body = p(n, c, scope, normal)
|
||||
|
||||
|
|
@ -1059,7 +1056,12 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
|||
scope.final.add c.genDestroy(params[i])
|
||||
#if optNimV2 in c.graph.config.globalOptions:
|
||||
# injectDefaultCalls(n, c)
|
||||
result = processScope(c, scope, body)
|
||||
result = optimize processScope(c, scope, body)
|
||||
dbg:
|
||||
echo ">---------transformed-to--------->"
|
||||
echo renderTree(result, {renderIds})
|
||||
|
||||
if g.config.arcToExpand.hasKey(owner.name.s):
|
||||
echo "--expandArc: ", owner.name.s
|
||||
echo renderTree(result, {renderIr})
|
||||
echo "-- end of expandArc ------------------------"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue