@@ -212,6 +212,11 @@ proc genSink(c: Con; dest, ri: PNode): PNode =
212
212
# we generate a fast assignment in this case:
213
213
result = newTree(nkFastAsgn, dest)
214
214
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
+
215
220
proc genCopyNoCheck(c: Con; dest, ri: PNode): PNode =
216
221
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
217
222
result = genOp(c, t, attachedAsgn, dest, ri)
284
289
sinkArg
285
290
286
291
proc 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
288
293
289
294
proc isClosureEnv(n: PNode): bool = n.kind == nkSym and n.sym.name.s[0 ] == ':'
290
295
@@ -547,7 +552,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
547
552
if ri.kind == nkEmpty and c.inLoop > 0 :
548
553
ri = genDefaultCall(v.typ, c, v.info)
549
554
if ri.kind != nkEmpty:
550
- let r = moveOrCopy(v, ri, c)
555
+ let r = moveOrCopy(v, ri, c, isFirstWrite = (c.inLoop == 0 ) )
551
556
result .add r
552
557
else : # keep the var but transform 'ri':
553
558
var v = copyNode(n)
@@ -566,7 +571,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
566
571
else :
567
572
if n[0 ].kind in {nkDotExpr, nkCheckedFieldExpr}:
568
573
cycleCheck(n, c)
569
- result = moveOrCopy(n[0 ], n[1 ], c)
574
+ result = moveOrCopy(n[0 ], n[1 ], c, isFirstWrite = false )
570
575
else :
571
576
result = copyNode(n)
572
577
result .add copyTree(n[0 ])
@@ -609,21 +614,21 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
609
614
for i in 0 ..< n.len:
610
615
result [i] = p(n[i], c, mode)
611
616
612
- proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
617
+ proc moveOrCopy(dest, ri: PNode; c: var Con, isFirstWrite: bool ): PNode =
613
618
case ri.kind
614
619
of nkCallKinds:
615
620
if isUnpackedTuple(dest):
616
621
result = newTree(nkFastAsgn, dest, p(ri, c, consumed))
617
622
else :
618
- result = genSink (c, dest, ri)
623
+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
619
624
result .add p(ri, c, consumed)
620
625
of nkBracketExpr:
621
626
if isUnpackedTuple(ri[0 ]):
622
627
# unpacking of tuple: take over elements
623
628
result = newTree(nkFastAsgn, dest, p(ri, c, consumed))
624
629
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c):
625
630
# Rule 3: `=sink`(x, z); wasMoved(z)
626
- var snk = genSink (c, dest, ri)
631
+ var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
627
632
snk.add ri
628
633
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
629
634
else :
@@ -634,53 +639,53 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
634
639
if ri.len > 0 and isDangerousSeq(ri.typ):
635
640
result = genCopy(c, dest, ri)
636
641
else :
637
- result = genSink (c, dest, ri)
642
+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
638
643
result .add p(ri, c, consumed)
639
644
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit.. nkNilLit:
640
- result = genSink (c, dest, ri)
645
+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
641
646
result .add p(ri, c, consumed)
642
647
of nkSym:
643
648
if isSinkParam(ri.sym):
644
649
# Rule 3: `=sink`(x, z); wasMoved(z)
645
650
sinkParamIsLastReadCheck(c, ri)
646
- var snk = genSink (c, dest, ri)
651
+ var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
647
652
snk.add ri
648
653
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
649
654
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
650
655
isLastRead(ri, c) and canBeMoved(c, dest.typ):
651
656
# Rule 3: `=sink`(x, z); wasMoved(z)
652
- var snk = genSink (c, dest, ri)
657
+ var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
653
658
snk.add ri
654
659
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
655
660
else :
656
661
result = genCopy(c, dest, ri)
657
662
result .add p(ri, c, consumed)
658
663
of nkHiddenSubConv, nkHiddenStdConv, nkConv:
659
664
when false :
660
- result = moveOrCopy(dest, ri[1 ], c)
665
+ result = moveOrCopy(dest, ri[1 ], c, isFirstWrite )
661
666
if not sameType(ri.typ, ri[1 ].typ):
662
667
let copyRi = copyTree(ri)
663
668
copyRi[1 ] = result [^ 1 ]
664
669
result [^ 1 ] = copyRi
665
670
else :
666
- result = genSink (c, dest, ri)
671
+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
667
672
result .add p(ri, c, sinkArg)
668
673
of nkObjDownConv, nkObjUpConv:
669
674
when false :
670
- result = moveOrCopy(dest, ri[0 ], c)
675
+ result = moveOrCopy(dest, ri[0 ], c, isFirstWrite )
671
676
let copyRi = copyTree(ri)
672
677
copyRi[0 ] = result [^ 1 ]
673
678
result [^ 1 ] = copyRi
674
679
else :
675
- result = genSink (c, dest, ri)
680
+ result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
676
681
result .add p(ri, c, sinkArg)
677
682
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt:
678
- handleNested(ri): moveOrCopy(dest, node, c)
683
+ handleNested(ri): moveOrCopy(dest, node, c, isFirstWrite )
679
684
else :
680
685
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and
681
686
canBeMoved(c, dest.typ):
682
687
# Rule 3: `=sink`(x, z); wasMoved(z)
683
- var snk = genSink (c, dest, ri)
688
+ var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
684
689
snk.add ri
685
690
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
686
691
else :
0 commit comments