summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2018-08-20 11:54:18 +0200
committerGitHub <noreply@github.com>2018-08-20 11:54:18 +0200
commit2def61606912625f3d20076e6686235996f25e62 (patch)
tree9b6de8742fa821b2e943b02fc48d81448bc91b8c
parentf87a91a3ec97a83a160984a029d55335a6beb978 (diff)
downloadNim-2def61606912625f3d20076e6686235996f25e62.tar.gz
exploit nil seqs for performance (#8688)
* changes $ for seqs to never produce 'nil'
* exploit the fact that empty seqs don't have to allocate in the code generator
-rw-r--r--compiler/ccgexprs.nim21
-rw-r--r--compiler/ccgtrav.nim2
-rw-r--r--lib/pure/xmltree.nim1
-rw-r--r--lib/system.nim5
-rw-r--r--tests/parallel/tsendtwice.nim12
-rw-r--r--tests/system/tostring.nim2
6 files changed, 23 insertions, 20 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 9ec034f67..b30d216f2 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1176,7 +1176,7 @@ proc genNew(p: BProc, e: PNode) =
     rawGenNew(p, a, nil)
   gcUsage(p.config, e)
 
-proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
+proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
   let seqtype = skipTypes(dest.t, abstractVarRange)
   let args = [getTypeDesc(p.module, seqtype),
               genTypeInfo(p.module, seqtype, dest.lode.info), length]
@@ -1187,17 +1187,23 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
       linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
     else:
       linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", dest.rdLoc)
-    call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
-    linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
+    if not lenIsZero:
+      call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
+      linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
   else:
-    call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
+    if lenIsZero:
+      call.r = rope"NIM_NIL"
+    else:
+      call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
     genAssignment(p, dest, call, {})
 
 proc genNewSeq(p: BProc, e: PNode) =
   var a, b: TLoc
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], b)
-  genNewSeqAux(p, a, b.rdLoc)
+  let lenIsZero = optNilSeqs notin p.options and
+    e[2].kind == nkIntLit and e[2].intVal == 0
+  genNewSeqAux(p, a, b.rdLoc, lenIsZero)
   gcUsage(p.config, e)
 
 proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
@@ -1297,7 +1303,8 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
   elif d.k == locNone:
     getTemp(p, n.typ, d)
   # generate call to newSeq before adding the elements per hand:
-  genNewSeqAux(p, dest[], intLiteral(sonsLen(n)))
+  genNewSeqAux(p, dest[], intLiteral(sonsLen(n)),
+    optNilSeqs notin p.options and n.len == 0)
   for i in countup(0, sonsLen(n) - 1):
     initLoc(arr, locExpr, n[i], OnHeap)
     arr.r = ropecg(p.module, "$1$3[$2]", rdLoc(dest[]), intLiteral(i), dataField(p))
@@ -1320,7 +1327,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
     getTemp(p, n.typ, d)
   # generate call to newSeq before adding the elements per hand:
   let L = int(lengthOrd(p.config, n.sons[1].typ))
-  genNewSeqAux(p, d, intLiteral(L))
+  genNewSeqAux(p, d, intLiteral(L), optNilSeqs notin p.options and L == 0)
   initLocExpr(p, n.sons[1], a)
   # bug #5007; do not produce excessive C source code:
   if L < 10:
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index e74d5a953..349cf2707 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -107,7 +107,7 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
   var i: TLoc
   getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
   let oldCode = p.s(cpsStmts)
-  lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
+  lineF(p, cpsStmts, "for ($1 = 0; $1 < ($2 ? $2->$3 : 0); $1++) {$n",
       [i.r, accessor, lenField(c.p)])
   let oldLen = p.s(cpsStmts).len
   genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.sons[0])
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
index 47658b59b..d536cfed0 100644
--- a/lib/pure/xmltree.nim
+++ b/lib/pure/xmltree.nim
@@ -377,7 +377,6 @@ proc findAll*(n: XmlNode, tag: string, result: var seq[XmlNode]) =
   ##   findAll(html, "img", tags)
   ##   for imgTag in tags:
   ##     process(imgTag)
-  assert isNil(result) == false
   assert n.k == xnElement
   for child in n.items():
     if child.k != xnElement:
diff --git a/lib/system.nim b/lib/system.nim
index 001eb19de..d61924a5b 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2530,10 +2530,7 @@ proc `$`*[T](x: seq[T]): string =
   ##
   ## .. code-block:: nim
   ##   $(@[23, 45]) == "@[23, 45]"
-  if x.isNil:
-    "nil"
-  else:
-    collectionToString(x, "@[", ", ", "]")
+  collectionToString(x, "@[", ", ", "]")
 
 # ----------------- GC interface ---------------------------------------------
 
diff --git a/tests/parallel/tsendtwice.nim b/tests/parallel/tsendtwice.nim
index 0700fc4da..0c923177a 100644
--- a/tests/parallel/tsendtwice.nim
+++ b/tests/parallel/tsendtwice.nim
@@ -1,11 +1,11 @@
 discard """
-  output: '''obj2 nil
-obj nil
-obj3 nil
+  output: '''obj2 @[]
+obj @[]
+obj3 @[]
 3
-obj2 nil
-obj nil
-obj3 nil'''
+obj2 @[]
+obj @[]
+obj3 @[]'''
   cmd: "nim c -r --threads:on $file"
 """
 
diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim
index 99299f203..42c07c0a4 100644
--- a/tests/system/tostring.nim
+++ b/tests/system/tostring.nim
@@ -24,7 +24,7 @@ doAssert "nan" == $(0.0/0.0)
 # nil tests
 # maybe a bit inconsistent in types
 var x: seq[string]
-doAssert "nil" == $(x)
+doAssert "@[]" == $(x)
 
 var y: string
 doAssert "" == $(y)