@@ -212,6 +212,11 @@ proc genSink(c: Con; dest, ri: PNode): PNode =
212212 # we generate a fast assignment in this case:
213213 result = newTree (nkFastAsgn, dest)
214214
215+ proc genSinkOrMemMove (c: Con ; dest, ri: PNode , isFirstWrite: bool ): PNode =
216+ # optimize sink call into a bitwise memcopy
217+ if isFirstWrite: newTree (nkFastAsgn, dest)
218+ else : genSink (c, dest, ri)
219+
215220proc genCopyNoCheck (c: Con ; dest, ri: PNode ): PNode =
216221 let t = dest.typ.skipTypes ({tyGenericInst, tyAlias, tySink})
217222 result = genOp (c, t, attachedAsgn, dest, ri)
284289 sinkArg
285290
286291proc p (n: PNode ; c: var Con ; mode: ProcessMode ): PNode
287- proc moveOrCopy (dest, ri: PNode ; c: var Con ): PNode
292+ proc moveOrCopy (dest, ri: PNode ; c: var Con , isFirstWrite: bool ): PNode
288293
289294proc isClosureEnv (n: PNode ): bool = n.kind == nkSym and n.sym.name.s[0 ] == ':'
290295
@@ -547,7 +552,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
547552 if ri.kind == nkEmpty and c.inLoop > 0 :
548553 ri = genDefaultCall (v.typ, c, v.info)
549554 if ri.kind != nkEmpty:
550- let r = moveOrCopy (v, ri, c)
555+ let r = moveOrCopy (v, ri, c, isFirstWrite = (c.inLoop == 0 ) )
551556 result .add r
552557 else : # keep the var but transform 'ri':
553558 var v = copyNode (n)
@@ -566,7 +571,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
566571 else :
567572 if n[0 ].kind in {nkDotExpr, nkCheckedFieldExpr}:
568573 cycleCheck (n, c)
569- result = moveOrCopy (n[0 ], n[1 ], c)
574+ result = moveOrCopy (n[0 ], n[1 ], c, isFirstWrite = false )
570575 else :
571576 result = copyNode (n)
572577 result .add copyTree (n[0 ])
@@ -609,21 +614,21 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
609614 for i in 0 ..< n.len:
610615 result [i] = p (n[i], c, mode)
611616
612- proc moveOrCopy (dest, ri: PNode ; c: var Con ): PNode =
617+ proc moveOrCopy (dest, ri: PNode ; c: var Con , isFirstWrite: bool ): PNode =
613618 case ri.kind
614619 of nkCallKinds:
615620 if isUnpackedTuple (dest):
616621 result = newTree (nkFastAsgn, dest, p (ri, c, consumed))
617622 else :
618- result = genSink (c, dest, ri)
623+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
619624 result .add p (ri, c, consumed)
620625 of nkBracketExpr:
621626 if isUnpackedTuple (ri[0 ]):
622627 # unpacking of tuple: take over elements
623628 result = newTree (nkFastAsgn, dest, p (ri, c, consumed))
624629 elif isAnalysableFieldAccess (ri, c.owner) and isLastRead (ri, c):
625630 # Rule 3: `=sink`(x, z); wasMoved(z)
626- var snk = genSink (c, dest, ri)
631+ var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
627632 snk.add ri
628633 result = newTree (nkStmtList, snk, genWasMoved (ri, c))
629634 else :
@@ -634,53 +639,53 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
634639 if ri.len > 0 and isDangerousSeq (ri.typ):
635640 result = genCopy (c, dest, ri)
636641 else :
637- result = genSink (c, dest, ri)
642+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
638643 result .add p (ri, c, consumed)
639644 of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit.. nkNilLit:
640- result = genSink (c, dest, ri)
645+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
641646 result .add p (ri, c, consumed)
642647 of nkSym:
643648 if isSinkParam (ri.sym):
644649 # Rule 3: `=sink`(x, z); wasMoved(z)
645650 sinkParamIsLastReadCheck (c, ri)
646- var snk = genSink (c, dest, ri)
651+ var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
647652 snk.add ri
648653 result = newTree (nkStmtList, snk, genWasMoved (ri, c))
649654 elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
650655 isLastRead (ri, c) and canBeMoved (c, dest.typ):
651656 # Rule 3: `=sink`(x, z); wasMoved(z)
652- var snk = genSink (c, dest, ri)
657+ var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
653658 snk.add ri
654659 result = newTree (nkStmtList, snk, genWasMoved (ri, c))
655660 else :
656661 result = genCopy (c, dest, ri)
657662 result .add p (ri, c, consumed)
658663 of nkHiddenSubConv, nkHiddenStdConv, nkConv:
659664 when false :
660- result = moveOrCopy (dest, ri[1 ], c)
665+ result = moveOrCopy (dest, ri[1 ], c, isFirstWrite )
661666 if not sameType (ri.typ, ri[1 ].typ):
662667 let copyRi = copyTree (ri)
663668 copyRi[1 ] = result [^ 1 ]
664669 result [^ 1 ] = copyRi
665670 else :
666- result = genSink (c, dest, ri)
671+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
667672 result .add p (ri, c, sinkArg)
668673 of nkObjDownConv, nkObjUpConv:
669674 when false :
670- result = moveOrCopy (dest, ri[0 ], c)
675+ result = moveOrCopy (dest, ri[0 ], c, isFirstWrite )
671676 let copyRi = copyTree (ri)
672677 copyRi[0 ] = result [^ 1 ]
673678 result [^ 1 ] = copyRi
674679 else :
675- result = genSink (c, dest, ri)
680+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
676681 result .add p (ri, c, sinkArg)
677682 of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt:
678- handleNested (ri): moveOrCopy (dest, node, c)
683+ handleNested (ri): moveOrCopy (dest, node, c, isFirstWrite )
679684 else :
680685 if isAnalysableFieldAccess (ri, c.owner) and isLastRead (ri, c) and
681686 canBeMoved (c, dest.typ):
682687 # Rule 3: `=sink`(x, z); wasMoved(z)
683- var snk = genSink (c, dest, ri)
688+ var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
684689 snk.add ri
685690 result = newTree (nkStmtList, snk, genWasMoved (ri, c))
686691 else :
0 commit comments