summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorcooldome <cdome@bk.ru>2020-01-02 21:58:01 +0000
committerAndreas Rumpf <rumpf_a@web.de>2020-01-02 22:58:01 +0100
commit002d50f1f064cae1dbf49987172f7af5d9e7d35c (patch)
treeba5fca61c580f00e5eb2ac5a2c3eee4994671988
parent0ff23e696c1e239214dfc2f1d2bb3e8fc6bf9493 (diff)
downloadNim-002d50f1f064cae1dbf49987172f7af5d9e7d35c.tar.gz
Sink to MemMove optimization in injectdestructors (#13002)
-rw-r--r--compiler/injectdestructors.nim37
-rw-r--r--compiler/liftdestructors.nim7
-rw-r--r--compiler/lowerings.nim10
-rw-r--r--tests/destructor/tmisc_destructors.nim2
4 files changed, 30 insertions, 26 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index d9a17cf7a..fad1eb03b 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -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)
@@ -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] == ':'
 
@@ -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)
@@ -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])
@@ -609,13 +614,13 @@ 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]):
@@ -623,7 +628,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
       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:
@@ -634,22 +639,22 @@ 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:
@@ -657,30 +662,30 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
       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:
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 932b24bb0..daf91954b 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -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)
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index cf8445820..d069bba84 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -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
@@ -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))
diff --git a/tests/destructor/tmisc_destructors.nim b/tests/destructor/tmisc_destructors.nim
index 7fc8a61c2..7d6995e4e 100644
--- a/tests/destructor/tmisc_destructors.nim
+++ b/tests/destructor/tmisc_destructors.nim
@@ -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 =