3434 uninit: IntSet # set of uninit'ed vars
3535 uninitComputed: bool
3636
37- const toDebug {.strdefine .} = " " # "server" # "serverNimAsyncContinue"
37+ const toDebug {.strdefine .} = " "
3838
3939template dbg (body) =
4040 when toDebug.len > 0 :
@@ -47,7 +47,7 @@ proc isLastRead(location: PNode; c: var Con; pc, comesFrom: int): int =
4747 case c.g[pc].kind
4848 of def:
4949 if defInstrTargets (c.g[pc], location):
50- # the path lead to a redefinition of 's' --> abandon it.
50+ # the path leads to a redefinition of 's' --> abandon it.
5151 return high (int )
5252 inc pc
5353 of use:
@@ -85,17 +85,63 @@ proc isLastRead(n: PNode; c: var Con): bool =
8585 instr = i
8686 break
8787
88- dbg:
89- echo " starting point for " , n, " is " , instr, " " , n.kind
88+ dbg: echo " starting point for " , n, " is " , instr, " " , n.kind
9089
9190 if instr < 0 : return false
9291 # we go through all paths beginning from 'instr+1' and need to
9392 # ensure that we don't find another 'use X' instruction.
9493 if instr+ 1 >= c.g.len: return true
9594
9695 result = isLastRead (n, c, instr+ 1 , - 1 ) >= 0
97- dbg:
98- echo " ugh " , c.otherRead.isNil, " " , result
96+ dbg: echo " ugh " , c.otherRead.isNil, " " , result
97+
98+ proc isFirstWrite (location: PNode ; c: var Con ; pc, comesFrom: int ; instr: int ): int =
99+ var pc = pc
100+ while pc < instr:
101+ case c.g[pc].kind
102+ of def:
103+ if defInstrTargets (c.g[pc], location):
104+ # a definition of 's' before ours makes ours not the first write
105+ return - 1
106+ inc pc
107+ of use:
108+ if useInstrTargets (c.g[pc], location):
109+ return - 1
110+ inc pc
111+ of goto:
112+ pc = pc + c.g[pc].dest
113+ of fork:
114+ # every branch must not contain a def/use of our location:
115+ let variantA = isFirstWrite (location, c, pc+ 1 , pc, instr)
116+ if variantA < 0 : return - 1
117+ var variantB = isFirstWrite (location, c, pc + c.g[pc].dest, pc, instr + c.g[pc].dest)
118+ if variantB < 0 : return - 1
119+ elif variantB == high (int ):
120+ variantB = variantA
121+ pc = variantB
122+ of InstrKind .join:
123+ let dest = pc + c.g[pc].dest
124+ if dest == comesFrom: return pc + 1
125+ inc pc
126+ return pc
127+
128+ proc isFirstWrite (n: PNode ; c: var Con ): bool =
129+ # first we need to search for the instruction that belongs to 'n':
130+ var instr = - 1
131+ let m = dfa.skipConvDfa (n)
132+
133+ for i in countdown (c.g.len- 1 , 0 ): # We search backwards here to treat loops correctly
134+ if c.g[i].kind == def and c.g[i].n == m:
135+ if instr < 0 :
136+ instr = i
137+ break
138+
139+ if instr < 0 : return false
140+ # we go through all paths going to 'instr' and need to
141+ # ensure that we don't find another 'def/use X' instruction.
142+ if instr == 0 : return true
143+
144+ result = isFirstWrite (n, c, 0 , - 1 , instr) >= 0
99145
100146proc initialized (code: ControlFlowGraph ; pc: int ,
101147 init, uninit: var IntSet ; comesFrom: int ): int =
@@ -200,22 +246,20 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} =
200246 else :
201247 result = t.attachedOps[attachedSink] != nil
202248
203- proc genSink (c: Con ; dest, ri: PNode ): PNode =
204- let t = dest.typ.skipTypes ({tyGenericInst, tyAlias, tySink})
205- let k = if t.attachedOps[attachedSink] != nil : attachedSink
206- else : attachedAsgn
207- if t.attachedOps[k] != nil :
208- result = genOp (c, t, k, dest, ri)
209- else :
210- # in rare cases only =destroy exists but no sink or assignment
211- # (see Pony object in tmove_objconstr.nim)
212- # we generate a fast assignment in this case:
249+ proc genSink (c: var Con ; dest, ri: PNode ): PNode =
250+ if isFirstWrite (dest, c): # optimize sink call into a bitwise memcopy
213251 result = newTree (nkFastAsgn, dest)
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)
252+ else :
253+ let t = dest.typ.skipTypes ({tyGenericInst, tyAlias, tySink})
254+ let k = if t.attachedOps[attachedSink] != nil : attachedSink
255+ else : attachedAsgn
256+ if t.attachedOps[k] != nil :
257+ result = genOp (c, t, k, dest, ri)
258+ else :
259+ # in rare cases only =destroy exists but no sink or assignment
260+ # (see Pony object in tmove_objconstr.nim)
261+ # we generate a fast assignment in this case:
262+ result = newTree (nkFastAsgn, dest)
219263
220264proc genCopyNoCheck (c: Con ; dest, ri: PNode ): PNode =
221265 let t = dest.typ.skipTypes ({tyGenericInst, tyAlias, tySink})
289333 sinkArg
290334
291335proc p (n: PNode ; c: var Con ; mode: ProcessMode ): PNode
292- proc moveOrCopy (dest, ri: PNode ; c: var Con , isFirstWrite: bool ): PNode
336+ proc moveOrCopy (dest, ri: PNode ; c: var Con ): PNode
293337
294338proc isClosureEnv (n: PNode ): bool = n.kind == nkSym and n.sym.name.s[0 ] == ':'
295339
@@ -552,7 +596,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
552596 if ri.kind == nkEmpty and c.inLoop > 0 :
553597 ri = genDefaultCall (v.typ, c, v.info)
554598 if ri.kind != nkEmpty:
555- let r = moveOrCopy (v, ri, c, isFirstWrite = (c.inLoop == 0 ) )
599+ let r = moveOrCopy (v, ri, c)
556600 result .add r
557601 else : # keep the var but transform 'ri':
558602 var v = copyNode (n)
@@ -572,7 +616,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
572616 if n[0 ].kind in {nkDotExpr, nkCheckedFieldExpr}:
573617 cycleCheck (n, c)
574618 assert n[1 ].kind notin {nkAsgn, nkFastAsgn}
575- result = moveOrCopy (n[0 ], n[1 ], c, isFirstWrite = false )
619+ result = moveOrCopy (n[0 ], n[1 ], c)
576620 else :
577621 result = copyNode (n)
578622 result .add copyTree (n[0 ])
@@ -615,21 +659,21 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
615659 for i in 0 ..< n.len:
616660 result [i] = p (n[i], c, mode)
617661
618- proc moveOrCopy (dest, ri: PNode ; c: var Con , isFirstWrite: bool ): PNode =
662+ proc moveOrCopy (dest, ri: PNode ; c: var Con ): PNode =
619663 case ri.kind
620664 of nkCallKinds:
621665 if isUnpackedTuple (dest):
622666 result = newTree (nkFastAsgn, dest, p (ri, c, consumed))
623667 else :
624- result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
668+ result = genSink (c, dest, ri)
625669 result .add p (ri, c, consumed)
626670 of nkBracketExpr:
627671 if isUnpackedTuple (ri[0 ]):
628672 # unpacking of tuple: take over elements
629673 result = newTree (nkFastAsgn, dest, p (ri, c, consumed))
630674 elif isAnalysableFieldAccess (ri, c.owner) and isLastRead (ri, c):
631675 # Rule 3: `=sink`(x, z); wasMoved(z)
632- var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
676+ var snk = genSink (c, dest, ri)
633677 snk.add ri
634678 result = newTree (nkStmtList, snk, genWasMoved (ri, c))
635679 else :
@@ -640,53 +684,53 @@ proc moveOrCopy(dest, ri: PNode; c: var Con, isFirstWrite: bool): PNode =
640684 if ri.len > 0 and isDangerousSeq (ri.typ):
641685 result = genCopy (c, dest, ri)
642686 else :
643- result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
687+ result = genSink (c, dest, ri)
644688 result .add p (ri, c, consumed)
645689 of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit.. nkNilLit:
646- result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
690+ result = genSink (c, dest, ri)
647691 result .add p (ri, c, consumed)
648692 of nkSym:
649693 if isSinkParam (ri.sym):
650694 # Rule 3: `=sink`(x, z); wasMoved(z)
651695 sinkParamIsLastReadCheck (c, ri)
652- var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
696+ var snk = genSink (c, dest, ri)
653697 snk.add ri
654698 result = newTree (nkStmtList, snk, genWasMoved (ri, c))
655699 elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
656700 isLastRead (ri, c) and canBeMoved (c, dest.typ):
657701 # Rule 3: `=sink`(x, z); wasMoved(z)
658- var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
702+ var snk = genSink (c, dest, ri)
659703 snk.add ri
660704 result = newTree (nkStmtList, snk, genWasMoved (ri, c))
661705 else :
662706 result = genCopy (c, dest, ri)
663707 result .add p (ri, c, consumed)
664708 of nkHiddenSubConv, nkHiddenStdConv, nkConv:
665709 when false :
666- result = moveOrCopy (dest, ri[1 ], c, isFirstWrite )
710+ result = moveOrCopy (dest, ri[1 ], c)
667711 if not sameType (ri.typ, ri[1 ].typ):
668712 let copyRi = copyTree (ri)
669713 copyRi[1 ] = result [^ 1 ]
670714 result [^ 1 ] = copyRi
671715 else :
672- result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
716+ result = genSink (c, dest, ri)
673717 result .add p (ri, c, sinkArg)
674718 of nkObjDownConv, nkObjUpConv:
675719 when false :
676- result = moveOrCopy (dest, ri[0 ], c, isFirstWrite )
720+ result = moveOrCopy (dest, ri[0 ], c)
677721 let copyRi = copyTree (ri)
678722 copyRi[0 ] = result [^ 1 ]
679723 result [^ 1 ] = copyRi
680724 else :
681- result = genSinkOrMemMove (c, dest, ri, isFirstWrite )
725+ result = genSink (c, dest, ri)
682726 result .add p (ri, c, sinkArg)
683727 of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt:
684- handleNested (ri): moveOrCopy (dest, node, c, isFirstWrite )
728+ handleNested (ri): moveOrCopy (dest, node, c)
685729 else :
686730 if isAnalysableFieldAccess (ri, c.owner) and isLastRead (ri, c) and
687731 canBeMoved (c, dest.typ):
688732 # Rule 3: `=sink`(x, z); wasMoved(z)
689- var snk = genSinkOrMemMove (c, dest, ri, isFirstWrite )
733+ var snk = genSink (c, dest, ri)
690734 snk.add ri
691735 result = newTree (nkStmtList, snk, genWasMoved (ri, c))
692736 else :
0 commit comments