Skip to content

Commit

Permalink
Sink to MemMove optimization in injectdestructors (#13002)
Browse files Browse the repository at this point in the history
  • Loading branch information
cooldome authored and Araq committed Jan 2, 2020
1 parent 0ff23e6 commit 002d50f
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 26 deletions.
37 changes: 21 additions & 16 deletions compiler/injectdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ proc genSink(c: Con; dest, ri: PNode): PNode =
# we generate a fast assignment in this case:
result = newTree(nkFastAsgn, dest)

proc genSinkOrMemMove(c: Con; dest, ri: PNode, isFirstWrite: bool): PNode =
# optimize sink call into a bitwise memcopy
if isFirstWrite: newTree(nkFastAsgn, dest)
else: genSink(c, dest, ri)

proc genCopyNoCheck(c: Con; dest, ri: PNode): PNode =
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
result = genOp(c, t, attachedAsgn, dest, ri)
Expand Down Expand Up @@ -284,7 +289,7 @@ type
sinkArg

proc p(n: PNode; c: var Con; mode: ProcessMode): PNode
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode
proc moveOrCopy(dest, ri: PNode; c: var Con, isFirstWrite: bool): PNode

proc isClosureEnv(n: PNode): bool = n.kind == nkSym and n.sym.name.s[0] == ':'

Expand Down Expand Up @@ -547,7 +552,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
if ri.kind == nkEmpty and c.inLoop > 0:
ri = genDefaultCall(v.typ, c, v.info)
if ri.kind != nkEmpty:
let r = moveOrCopy(v, ri, c)
let r = moveOrCopy(v, ri, c, isFirstWrite = (c.inLoop == 0))
result.add r
else: # keep the var but transform 'ri':
var v = copyNode(n)
Expand All @@ -566,7 +571,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
else:
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
cycleCheck(n, c)
result = moveOrCopy(n[0], n[1], c)
result = moveOrCopy(n[0], n[1], c, isFirstWrite = false)
else:
result = copyNode(n)
result.add copyTree(n[0])
Expand Down Expand Up @@ -609,21 +614,21 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
for i in 0..<n.len:
result[i] = p(n[i], c, mode)

proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
proc moveOrCopy(dest, ri: PNode; c: var Con, isFirstWrite: bool): PNode =
case ri.kind
of nkCallKinds:
if isUnpackedTuple(dest):
result = newTree(nkFastAsgn, dest, p(ri, c, consumed))
else:
result = genSink(c, dest, ri)
result = genSinkOrMemMove(c, dest, ri, isFirstWrite)
result.add p(ri, c, consumed)
of nkBracketExpr:
if isUnpackedTuple(ri[0]):
# unpacking of tuple: take over elements
result = newTree(nkFastAsgn, dest, p(ri, c, consumed))
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c):
# Rule 3: `=sink`(x, z); wasMoved(z)
var snk = genSink(c, dest, ri)
var snk = genSinkOrMemMove(c, dest, ri, isFirstWrite)
snk.add ri
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
else:
Expand All @@ -634,53 +639,53 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
if ri.len > 0 and isDangerousSeq(ri.typ):
result = genCopy(c, dest, ri)
else:
result = genSink(c, dest, ri)
result = genSinkOrMemMove(c, dest, ri, isFirstWrite)
result.add p(ri, c, consumed)
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
result = genSink(c, dest, ri)
result = genSinkOrMemMove(c, dest, ri, isFirstWrite)
result.add p(ri, c, consumed)
of nkSym:
if isSinkParam(ri.sym):
# Rule 3: `=sink`(x, z); wasMoved(z)
sinkParamIsLastReadCheck(c, ri)
var snk = genSink(c, dest, ri)
var snk = genSinkOrMemMove(c, dest, ri, isFirstWrite)
snk.add ri
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
isLastRead(ri, c) and canBeMoved(c, dest.typ):
# Rule 3: `=sink`(x, z); wasMoved(z)
var snk = genSink(c, dest, ri)
var snk = genSinkOrMemMove(c, dest, ri, isFirstWrite)
snk.add ri
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
else:
result = genCopy(c, dest, ri)
result.add p(ri, c, consumed)
of nkHiddenSubConv, nkHiddenStdConv, nkConv:
when false:
result = moveOrCopy(dest, ri[1], c)
result = moveOrCopy(dest, ri[1], c, isFirstWrite)
if not sameType(ri.typ, ri[1].typ):
let copyRi = copyTree(ri)
copyRi[1] = result[^1]
result[^1] = copyRi
else:
result = genSink(c, dest, ri)
result = genSinkOrMemMove(c, dest, ri, isFirstWrite)
result.add p(ri, c, sinkArg)
of nkObjDownConv, nkObjUpConv:
when false:
result = moveOrCopy(dest, ri[0], c)
result = moveOrCopy(dest, ri[0], c, isFirstWrite)
let copyRi = copyTree(ri)
copyRi[0] = result[^1]
result[^1] = copyRi
else:
result = genSink(c, dest, ri)
result = genSinkOrMemMove(c, dest, ri, isFirstWrite)
result.add p(ri, c, sinkArg)
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt:
handleNested(ri): moveOrCopy(dest, node, c)
handleNested(ri): moveOrCopy(dest, node, c, isFirstWrite)
else:
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and
canBeMoved(c, dest.typ):
# Rule 3: `=sink`(x, z); wasMoved(z)
var snk = genSink(c, dest, ri)
var snk = genSinkOrMemMove(c, dest, ri, isFirstWrite)
snk.add ri
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
else:
Expand Down
7 changes: 0 additions & 7 deletions compiler/liftdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -253,13 +253,6 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
body.add newDeepCopyCall(op, x, y)
result = true

proc addVar(father, v, value: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart[0] = v
vpart[1] = newNodeI(nkEmpty, v.info)
vpart[2] = value
father.add vpart

proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.fn, c.info)
temp.typ = getSysType(c.g, body.info, tyInt)
Expand Down
10 changes: 8 additions & 2 deletions compiler/lowerings.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ proc addVar*(father, v: PNode) =
vpart[2] = vpart[1]
father.add vpart

proc addVar*(father, v, value: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart[0] = v
vpart[1] = newNodeI(nkEmpty, v.info)
vpart[2] = value
father.add vpart

proc newAsgnStmt*(le, ri: PNode): PNode =
result = newNodeI(nkAsgn, le.info, 2)
result[0] = le
Expand All @@ -63,10 +70,9 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =

var v = newNodeI(nkVarSection, value.info)
let tempAsNode = newSymNode(temp)
v.addVar(tempAsNode)
v.addVar(tempAsNode, value)
result.add(v)

result.add newAsgnStmt(tempAsNode, value)
for i in 0..<n.len-2:
if n[i].kind == nkSym: v.addVar(n[i])
result.add newAsgnStmt(n[i], newTupleAccess(g, tempAsNode, i))
Expand Down
2 changes: 1 addition & 1 deletion tests/destructor/tmisc_destructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ proc test(): auto =
var (a, b, _) = test()

doAssert assign_counter == 0
doAssert sink_counter == 6
doAssert sink_counter == 3

# bug #11510
proc main =
Expand Down

0 comments on commit 002d50f

Please sign in to comment.