Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sink to MemMove optimization in injectdestructors #13002

Merged
merged 12 commits into from
Jan 2, 2020
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)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed lowerTupleUnpacking because now pattern var x = value is optimized while var x; x = ... is not.

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