linearScanEnd pragma; string case statement optimization

This commit is contained in:
Araq 2011-03-14 23:57:41 +01:00
commit 8d734244b1
26 changed files with 537 additions and 252 deletions

View file

@ -123,6 +123,10 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/procfind.c -o build/1_1/procfind.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/procfind.c -o build/1_1/procfind.o %CC% %COMP_FLAGS% -Ibuild -c build/1_1/procfind.c -o build/1_1/procfind.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/pragmas.c -o build/1_1/pragmas.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/pragmas.c -o build/1_1/pragmas.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/pragmas.c -o build/1_1/pragmas.o %CC% %COMP_FLAGS% -Ibuild -c build/1_1/pragmas.c -o build/1_1/pragmas.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/semtypinst.c -o build/1_1/semtypinst.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/semtypinst.c -o build/1_1/semtypinst.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/sigmatch.c -o build/1_1/sigmatch.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/sigmatch.c -o build/1_1/sigmatch.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/suggest.c -o build/1_1/suggest.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/suggest.c -o build/1_1/suggest.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/suggest.c -o build/1_1/suggest.o %CC% %COMP_FLAGS% -Ibuild -c build/1_1/suggest.c -o build/1_1/suggest.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/docgen.c -o build/1_1/docgen.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/docgen.c -o build/1_1/docgen.o
@ -139,8 +143,6 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/cgmeth.c -o build/1_1/cgmeth.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/cgmeth.c -o build/1_1/cgmeth.o %CC% %COMP_FLAGS% -Ibuild -c build/1_1/cgmeth.c -o build/1_1/cgmeth.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/ecmasgen.c -o build/1_1/ecmasgen.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/ecmasgen.c -o build/1_1/ecmasgen.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/ecmasgen.c -o build/1_1/ecmasgen.o %CC% %COMP_FLAGS% -Ibuild -c build/1_1/ecmasgen.c -o build/1_1/ecmasgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/interact.c -o build/1_1/interact.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/interact.c -o build/1_1/interact.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/passaux.c -o build/1_1/passaux.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/passaux.c -o build/1_1/passaux.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/passaux.c -o build/1_1/passaux.o %CC% %COMP_FLAGS% -Ibuild -c build/1_1/passaux.c -o build/1_1/passaux.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/depends.c -o build/1_1/depends.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/depends.c -o build/1_1/depends.o
@ -150,8 +152,8 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/transf.c -o build/1_1/transf.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o %CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/semtypinst.o build/1_1/sigmatch.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/semtypinst.o build/1_1/sigmatch.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
ECHO SUCCESS ECHO SUCCESS

View file

@ -2648,6 +2648,53 @@ The `hint`:idx: pragma is used to make the compiler output a hint message with
the given content. Compilation continues after the hint. the given content. Compilation continues after the hint.
linearScanEnd pragma
--------------------
The `linearScanEnd`:idx: pragma can be used to tell the compiler how to
compile a Nimrod `case`:idx: statement. Syntactially it has to be used as a
statement:
.. code-block:: nimrod
case myInt
of 0:
echo "most common case"
of 1:
{.linearScanEnd.}
echo "second most common case"
of 2: echo "unlikely: use branch table"
else: echo "unlikely too: use branch table for ", myInt
In the example, the case branches ``0`` and ``1`` are much more common than
the other cases. Therefore the generated assembler code should test for these
values first, so that the CPU's branch predictor has a good chance to succeed
(avoiding an expensive CPU pipeline stall). The other cases might be put into a
jump table for O(1) overhead, but at the cost of a (very likely) pipeline
stall.
The ``linearScanEnd`` pragma should be put into the last branch that should be
tested against via linear scanning. If put into the last branch of the
whole ``case`` statement, the whole ``case`` statement uses linear scanning.
unroll pragma
-------------
The `unroll`:idx: pragma can be used to tell the compiler that it should unroll
a `for`:idx: or `while`:idx: loop for runtime efficiency:
.. code-block:: nimrod
proc searchChar(s: string, c: char): int =
for i in 0 .. s.high:
{.unroll: 4.}
if s[i] == c: return i
result = -1
In the above example, the search loop is unrolled by a factor 4. The unroll
factor can be left out too; the compiler then chooses an appropriate unroll
factor.
**Note**: Currently the compiler recognizes but ignores this pragma.
compilation option pragmas compilation option pragmas
-------------------------- --------------------------
The listed pragmas here can be used to override the code generation options The listed pragmas here can be used to override the code generation options

View file

@ -293,10 +293,26 @@ However it is not efficient to do:
.. code-block:: Nimrod .. code-block:: Nimrod
var s = varA # assignment has to copy the whole string into a new buffer! var s = varA # assignment has to copy the whole string into a new buffer!
.. The compiler optimizes string case statements: A hashing scheme is used for them
String case statements are optimized too. A hashing scheme is used for them if several different string constants are used. So code like this is reasonably
if several different string constants are used. This is likely to be more efficient:
efficient than any hand-coded scheme.
.. code-block:: Nimrod
case normalize(k.key)
of "name": c.name = v
of "displayname": c.displayName = v
of "version": c.version = v
of "os": c.oses = split(v, {';'})
of "cpu": c.cpus = split(v, {';'})
of "authors": c.authors = split(v, {';'})
of "description": c.description = v
of "app":
case normalize(v)
of "console": c.app = appConsole
of "gui": c.app = appGUI
else: quit(errorStr(p, "expected: console or gui"))
of "license": c.license = UnixToNativePath(k.value)
else: quit(errorStr(p, "unknown variable: " & k.key))
.. ..

View file

@ -88,8 +88,6 @@ if [ $# -eq 1 ] ; then
chmod 644 $docdir/abstypes.txt chmod 644 $docdir/abstypes.txt
cp doc/advopt.txt $docdir/advopt.txt || exit 1 cp doc/advopt.txt $docdir/advopt.txt || exit 1
chmod 644 $docdir/advopt.txt chmod 644 $docdir/advopt.txt
cp doc/altsyn.txt $docdir/altsyn.txt || exit 1
chmod 644 $docdir/altsyn.txt
cp doc/apis.txt $docdir/apis.txt || exit 1 cp doc/apis.txt $docdir/apis.txt || exit 1
chmod 644 $docdir/apis.txt chmod 644 $docdir/apis.txt
cp doc/astspec.txt $docdir/astspec.txt || exit 1 cp doc/astspec.txt $docdir/astspec.txt || exit 1
@ -330,6 +328,8 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/core/marshal.nim chmod 644 $libdir/core/marshal.nim
cp lib/core/threads.nim $libdir/core/threads.nim || exit 1 cp lib/core/threads.nim $libdir/core/threads.nim || exit 1
chmod 644 $libdir/core/threads.nim chmod 644 $libdir/core/threads.nim
cp lib/pure/algorithm.nim $libdir/pure/algorithm.nim || exit 1
chmod 644 $libdir/pure/algorithm.nim
cp lib/pure/base64.nim $libdir/pure/base64.nim || exit 1 cp lib/pure/base64.nim $libdir/pure/base64.nim || exit 1
chmod 644 $libdir/pure/base64.nim chmod 644 $libdir/pure/base64.nim
cp lib/pure/browsers.nim $libdir/pure/browsers.nim || exit 1 cp lib/pure/browsers.nim $libdir/pure/browsers.nim || exit 1
@ -344,6 +344,8 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/pure/cookies.nim chmod 644 $libdir/pure/cookies.nim
cp lib/pure/dynlib.nim $libdir/pure/dynlib.nim || exit 1 cp lib/pure/dynlib.nim $libdir/pure/dynlib.nim || exit 1
chmod 644 $libdir/pure/dynlib.nim chmod 644 $libdir/pure/dynlib.nim
cp lib/pure/gentabs.nim $libdir/pure/gentabs.nim || exit 1
chmod 644 $libdir/pure/gentabs.nim
cp lib/pure/hashes.nim $libdir/pure/hashes.nim || exit 1 cp lib/pure/hashes.nim $libdir/pure/hashes.nim || exit 1
chmod 644 $libdir/pure/hashes.nim chmod 644 $libdir/pure/hashes.nim
cp lib/pure/htmlparser.nim $libdir/pure/htmlparser.nim || exit 1 cp lib/pure/htmlparser.nim $libdir/pure/htmlparser.nim || exit 1

View file

@ -406,14 +406,16 @@ proc ParseInt*(s: string): int {.noSideEffect, procvar,
## Parses a decimal integer value contained in `s`. If `s` is not ## Parses a decimal integer value contained in `s`. If `s` is not
## a valid integer, `EInvalidValue` is raised. ## a valid integer, `EInvalidValue` is raised.
var L = parseutils.parseInt(s, result, 0) var L = parseutils.parseInt(s, result, 0)
if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s) if L != s.len or L == 0:
raise newException(EInvalidValue, "invalid integer: " & s)
proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect, procvar, proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect, procvar,
rtl, extern: "nsuParseBiggestInt".} = rtl, extern: "nsuParseBiggestInt".} =
## Parses a decimal integer value contained in `s`. If `s` is not ## Parses a decimal integer value contained in `s`. If `s` is not
## a valid integer, `EInvalidValue` is raised. ## a valid integer, `EInvalidValue` is raised.
var L = parseutils.parseBiggestInt(s, result, 0) var L = parseutils.parseBiggestInt(s, result, 0)
if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s) if L != s.len or L == 0:
raise newException(EInvalidValue, "invalid integer: " & s)
proc ParseFloat*(s: string): float {.noSideEffect, procvar, proc ParseFloat*(s: string): float {.noSideEffect, procvar,
rtl, extern: "nsuParseFloat".} = rtl, extern: "nsuParseFloat".} =
@ -421,7 +423,8 @@ proc ParseFloat*(s: string): float {.noSideEffect, procvar,
## a valid floating point number, `EInvalidValue` is raised. ``NAN``, ## a valid floating point number, `EInvalidValue` is raised. ``NAN``,
## ``INF``, ``-INF`` are also supported (case insensitive comparison). ## ``INF``, ``-INF`` are also supported (case insensitive comparison).
var L = parseutils.parseFloat(s, result, 0) var L = parseutils.parseFloat(s, result, 0)
if L != s.len: raise newException(EInvalidValue, "invalid float: " & s) if L != s.len or L == 0:
raise newException(EInvalidValue, "invalid float: " & s)
proc ParseHexInt*(s: string): int {.noSideEffect, procvar, proc ParseHexInt*(s: string): int {.noSideEffect, procvar,
rtl, extern: "nsuParseHexInt".} = rtl, extern: "nsuParseHexInt".} =

View file

@ -1198,12 +1198,12 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
# ----------------- GC interface --------------------------------------------- # ----------------- GC interface ---------------------------------------------
proc GC_disable*() {.rtl.} proc GC_disable*() {.rtl, inl.}
## disables the GC. If called n-times, n calls to `GC_enable` are needed to ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
## reactivate the GC. Note that in most circumstances one should only disable ## reactivate the GC. Note that in most circumstances one should only disable
## the mark and sweep phase with `GC_disableMarkAndSweep`. ## the mark and sweep phase with `GC_disableMarkAndSweep`.
proc GC_enable*() {.rtl.} proc GC_enable*() {.rtl, inl.}
## enables the GC again. ## enables the GC again.
proc GC_fullCollect*() {.rtl.} proc GC_fullCollect*() {.rtl.}

View file

@ -7,9 +7,7 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
#when defined(debugGC): proc genericAssignAux(dest, src: Pointer, mt: PNimType)
# {.define: logAssign.}
proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.}
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) = proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
var var
d = cast[TAddress](dest) d = cast[TAddress](dest)
@ -17,7 +15,7 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
case n.kind case n.kind
of nkNone: assert(false) of nkNone: assert(false)
of nkSlot: of nkSlot:
genericAssign(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset), genericAssignAux(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
n.typ) n.typ)
of nkList: of nkList:
for i in 0..n.len-1: for i in 0..n.len-1:
@ -28,7 +26,7 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
var m = selectBranch(src, n) var m = selectBranch(src, n)
if m != nil: genericAssignAux(dest, src, m) if m != nil: genericAssignAux(dest, src, m)
proc genericAssign(dest, src: Pointer, mt: PNimType) = proc genericAssignAux(dest, src: Pointer, mt: PNimType) =
var var
d = cast[TAddress](dest) d = cast[TAddress](dest)
s = cast[TAddress](src) s = cast[TAddress](src)
@ -47,7 +45,7 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
newObj(mt, seq.len * mt.base.size + GenericSeqSize)) newObj(mt, seq.len * mt.base.size + GenericSeqSize))
var dst = cast[taddress](cast[ppointer](dest)^) var dst = cast[taddress](cast[ppointer](dest)^)
for i in 0..seq.len-1: for i in 0..seq.len-1:
genericAssign( genericAssignAux(
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
cast[pointer](cast[taddress](s2) +% i *% mt.base.size +% cast[pointer](cast[taddress](s2) +% i *% mt.base.size +%
GenericSeqSize), GenericSeqSize),
@ -60,7 +58,7 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
genericAssignAux(dest, src, mt.node) genericAssignAux(dest, src, mt.node)
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
for i in 0..(mt.size div mt.base.size)-1: for i in 0..(mt.size div mt.base.size)-1:
genericAssign(cast[pointer](d +% i*% mt.base.size), genericAssignAux(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base) cast[pointer](s +% i*% mt.base.size), mt.base)
of tyString: # a leaf of tyString: # a leaf
var s2 = cast[ppointer](s)^ var s2 = cast[ppointer](s)^
@ -75,6 +73,11 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
else: else:
copyMem(dest, src, mt.size) # copy raw bits copyMem(dest, src, mt.size) # copy raw bits
proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
GC_disable()
genericAssignAux(dest, src, mt)
GC_enable()
proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} = proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
var src = src # ugly, but I like to stress the parser sometimes :-) var src = src # ugly, but I like to stress the parser sometimes :-)
genericAssign(dest, addr(src), mt) genericAssign(dest, addr(src), mt)

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.

View file

@ -269,7 +269,8 @@ type
tfNoSideEffect, # procedure type does not allow side effects tfNoSideEffect, # procedure type does not allow side effects
tfFinal, # is the object final? tfFinal, # is the object final?
tfAcyclic, # type is acyclic (for GC optimization) tfAcyclic, # type is acyclic (for GC optimization)
tfEnumHasWholes # enum cannot be mapped into a range tfEnumHasWholes, # enum cannot be mapped into a range
tfShallow # type can be shallow copied on assignment
TTypeFlags* = set[TTypeFlag] TTypeFlags* = set[TTypeFlag]

View file

@ -215,6 +215,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)]) [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else: else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyObject:
# XXX: check for subtyping?
if needsComplexAssignment(dest.t):
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
if needsComplexAssignment(dest.t): if needsComplexAssignment(dest.t):
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
@ -223,12 +230,6 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
appcg(p, cpsStmts, appcg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n", "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
[rdLoc(dest), rdLoc(src)]) [rdLoc(dest), rdLoc(src)])
of tyObject: # XXX: check for subtyping?
if needsComplexAssignment(dest.t):
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyOpenArray: of tyOpenArray:
# open arrays are always on the stack - really? What if a sequence is # open arrays are always on the stack - really? What if a sequence is
# passed to an open array? # passed to an open array?

View file

@ -10,6 +10,10 @@
const const
RangeExpandLimit = 256 # do not generate ranges RangeExpandLimit = 256 # do not generate ranges
# over 'RangeExpandLimit' elements # over 'RangeExpandLimit' elements
stringCaseThreshold = 8
# above X strings a hash-switch for strings is generated
# this version sets it too high to avoid hashing, because this has not
# been tested for a long time
proc genLineDir(p: BProc, t: PNode) = proc genLineDir(p: BProc, t: PNode) =
var line = toLinenumber(t.info) # BUGFIX var line = toLinenumber(t.info) # BUGFIX
@ -229,13 +233,6 @@ proc genRaiseStmt(p: BProc, t: PNode) =
else: else:
appcg(p, cpsStmts, "#reraiseException();" & tnl) appcg(p, cpsStmts, "#reraiseException();" & tnl)
const
stringCaseThreshold = 100000
# above X strings a hash-switch for strings is generated
# this version sets it too high to avoid hashing, because this has not
# been tested for a long time
# XXX test and enable this optimization!
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
rangeFormat, eqFormat: TFormatStr, labl: TLabel) = rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
var var
@ -251,90 +248,68 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
initLocExpr(p, b.sons[i], x) initLocExpr(p, b.sons[i], x)
appcg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl]) appcg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
proc genCaseSecondPass(p: BProc, t: PNode, labId: int) = proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel =
var Lend = getLabel(p) var Lend = getLabel(p)
for i in countup(1, sonsLen(t) - 1): for i in 1..until:
appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(labId + i)]) appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(labId + i)])
if t.sons[i].kind == nkOfBranch: # else statement if t.sons[i].kind == nkOfBranch:
var length = sonsLen(t.sons[i]) var length = sonsLen(t.sons[i])
genStmts(p, t.sons[i].sons[length - 1]) genStmts(p, t.sons[i].sons[length - 1])
appf(p.s[cpsStmts], "goto $1;$n", [Lend]) appf(p.s[cpsStmts], "goto $1;$n", [Lend])
else: else:
genStmts(p, t.sons[i].sons[0]) genStmts(p, t.sons[i].sons[0])
fixLabel(p, Lend) result = Lend
proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) = proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr,
until: int, a: TLoc): TLabel =
# generate a C-if statement for a Nimrod case statement # generate a C-if statement for a Nimrod case statement
var a: TLoc
initLocExpr(p, t.sons[0], a) # fist pass: generate ifs+goto:
var labId = p.labels var labId = p.labels
for i in countup(1, sonsLen(t) - 1): for i in 1..until:
inc(p.labels) inc(p.labels)
if t.sons[i].kind == nkOfBranch: # else statement if t.sons[i].kind == nkOfBranch: # else statement
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat, genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
con("LA", toRope(p.labels))) con("LA", toRope(p.labels)))
else: else:
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)]) appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
genCaseSecondPass(p, t, labId) if until < t.len-1:
inc(p.labels)
proc hashString(s: string): biggestInt = var gotoTarget = p.labels
var appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(gotoTarget)])
a: int32 result = genCaseSecondPass(p, t, labId, until)
b: int64 appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(gotoTarget)])
if CPU[targetCPU].bit == 64:
# we have to use the same bitwidth
# as the target CPU
b = 0
for i in countup(0, len(s) - 1):
b = b +% Ord(s[i])
b = b +% `shl`(b, 10)
b = b xor `shr`(b, 6)
b = b +% `shl`(b, 3)
b = b xor `shr`(b, 11)
b = b +% `shl`(b, 15)
result = b
else: else:
a = 0 result = genCaseSecondPass(p, t, labId, until)
for i in countup(0, len(s) - 1):
a = a +% int32(Ord(s[i]))
a = a +% `shl`(a, int32(10))
a = a xor `shr`(a, int32(6))
a = a +% `shl`(a, int32(3))
a = a xor `shr`(a, int32(11))
a = a +% `shl`(a, int32(15))
result = a
type proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) =
TRopeSeq = seq[PRope] var a: TLoc
initLocExpr(p, t.sons[0], a)
var Lend = genIfForCaseUntil(p, t, rangeFormat, eqFormat, sonsLen(t)-1, a)
fixLabel(p, Lend)
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel, proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
branches: var TRopeSeq) = branches: var openArray[PRope]) =
var var x: TLoc
length, j: int var length = sonsLen(b)
x: TLoc
length = sonsLen(b)
for i in countup(0, length - 2): for i in countup(0, length - 2):
assert(b.sons[i].kind != nkRange) assert(b.sons[i].kind != nkRange)
initLocExpr(p, b.sons[i], x) initLocExpr(p, b.sons[i], x)
assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit}) assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
j = int(hashString(b.sons[i].strVal) and high(branches)) var j = int(hashString(b.sons[i].strVal) and high(branches))
appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n", appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
[rdLoc(e), rdLoc(x), labl]) [rdLoc(e), rdLoc(x), labl])
proc genStringCase(p: BProc, t: PNode) = proc genStringCase(p: BProc, t: PNode) =
var
strings, bitMask, labId: int
a: TLoc
branches: TRopeSeq
# count how many constant strings there are in the case: # count how many constant strings there are in the case:
strings = 0 var strings = 0
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):
if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1) if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
if strings > stringCaseThreshold: if strings > stringCaseThreshold:
bitMask = math.nextPowerOfTwo(strings) - 1 var bitMask = math.nextPowerOfTwo(strings) - 1
var branches: seq[PRope]
newSeq(branches, bitMask + 1) newSeq(branches, bitMask + 1)
var a: TLoc
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto: initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
labId = p.labels var labId = p.labels
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):
inc(p.labels) inc(p.labels)
if t.sons[i].kind == nkOfBranch: if t.sons[i].kind == nkOfBranch:
@ -353,7 +328,8 @@ proc genStringCase(p: BProc, t: PNode) =
if t.sons[sonsLen(t) - 1].kind != nkOfBranch: if t.sons[sonsLen(t) - 1].kind != nkOfBranch:
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)]) appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
# third pass: generate statements # third pass: generate statements
genCaseSecondPass(p, t, labId) var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1)
fixLabel(p, Lend)
else: else:
genCaseGeneric(p, t, "", "if (#eqStrings($1, $2)) goto $3;$n") genCaseGeneric(p, t, "", "if (#eqStrings($1, $2)) goto $3;$n")
@ -363,57 +339,61 @@ proc branchHasTooBigRange(b: PNode): bool =
if (b.sons[i].Kind == nkRange) and if (b.sons[i].Kind == nkRange) and
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit: b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
return true return true
result = false
proc genOrdinalCase(p: BProc, t: PNode) = proc IfSwitchSplitPoint(p: BProc, n: PNode): int =
# We analyse if we have a too big switch range. If this is the case, for i in 1..n.len-1:
# we generate an ordinary if statement and rely on the C compiler var branch = n[i]
# to produce good code. var stmtBlock = lastSon(branch)
var if stmtBlock.stmtsContainPragma(wLinearScanEnd):
canGenerateSwitch, hasDefault: bool result = i
length: int elif hasSwitchRange notin CC[ccompiler].props:
a: TLoc if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
v: PNode result = i
canGenerateSwitch = true
if not (hasSwitchRange in CC[ccompiler].props): proc genOrdinalCase(p: BProc, n: PNode) =
for i in countup(1, sonsLen(t) - 1): # analyse 'case' statement:
if (t.sons[i].kind == nkOfBranch) and branchHasTooBigRange(t.sons[i]): var splitPoint = IfSwitchSplitPoint(p, n)
canGenerateSwitch = false
break # generate if part (might be empty):
if canGenerateSwitch: var a: TLoc
initLocExpr(p, t.sons[0], a) initLocExpr(p, n.sons[0], a)
var Lend = if splitPoint > 0: genIfForCaseUntil(p, n,
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
splitPoint, a) else: nil
# generate switch part (might be empty):
if splitPoint+1 < n.len:
appf(p.s[cpsStmts], "switch ($1) {$n", [rdCharLoc(a)]) appf(p.s[cpsStmts], "switch ($1) {$n", [rdCharLoc(a)])
hasDefault = false var hasDefault = false
for i in countup(1, sonsLen(t) - 1): for i in splitPoint+1 .. < n.len:
if t.sons[i].kind == nkOfBranch: var branch = n[i]
length = sonsLen(t.sons[i]) if branch.kind == nkOfBranch:
for j in countup(0, length - 2): var length = branch.len
if t.sons[i].sons[j].kind == nkRange: for j in 0 .. length-2:
# a range if branch[j].kind == nkRange:
if hasSwitchRange in CC[ccompiler].props: if hasSwitchRange in CC[ccompiler].props:
appf(p.s[cpsStmts], "case $1 ... $2:$n", [ appf(p.s[cpsStmts], "case $1 ... $2:$n", [
genLiteral(p, t.sons[i].sons[j].sons[0]), genLiteral(p, branch[j][0]),
genLiteral(p, t.sons[i].sons[j].sons[1])]) genLiteral(p, branch[j][1])])
else: else:
v = copyNode(t.sons[i].sons[j].sons[0]) var v = copyNode(branch[j][0])
while (v.intVal <= t.sons[i].sons[j].sons[1].intVal): while v.intVal <= branch[j][1].intVal:
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, v)]) appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, v)])
Inc(v.intVal) Inc(v.intVal)
else: else:
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, t.sons[i].sons[j])]) appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, branch[j])])
genStmts(p, t.sons[i].sons[length - 1]) genStmts(p, branch[length-1])
else: else:
# else part of case statement: # else part of case statement:
app(p.s[cpsStmts], "default:" & tnl) app(p.s[cpsStmts], "default:" & tnl)
genStmts(p, t.sons[i].sons[0]) genStmts(p, branch[0])
hasDefault = true hasDefault = true
app(p.s[cpsStmts], "break;" & tnl) app(p.s[cpsStmts], "break;" & tnl)
if (hasAssume in CC[ccompiler].props) and not hasDefault: if (hasAssume in CC[ccompiler].props) and not hasDefault:
app(p.s[cpsStmts], "default: __assume(0);" & tnl) app(p.s[cpsStmts], "default: __assume(0);" & tnl)
app(p.s[cpsStmts], '}' & tnl) app(p.s[cpsStmts], '}' & tnl)
else: if Lend != nil: fixLabel(p, Lend)
genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
"if ($1 == $2) goto $3;$n")
proc genCaseStmt(p: BProc, t: PNode) = proc genCaseStmt(p: BProc, t: PNode) =
genLineDir(p, t) genLineDir(p, t)
@ -424,7 +404,6 @@ proc genCaseStmt(p: BProc, t: PNode) =
genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n", genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
"if ($1 == $2) goto $3;$n") "if ($1 == $2) goto $3;$n")
else: else:
# ordinal type: generate a switch statement
genOrdinalCase(p, t) genOrdinalCase(p, t)
proc hasGeneralExceptSection(t: PNode): bool = proc hasGeneralExceptSection(t: PNode): bool =
@ -629,9 +608,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
proc genPragma(p: BProc, n: PNode) = proc genPragma(p: BProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it case whichPragma(it)
if key.kind == nkIdent:
case whichKeyword(key.ident)
of wEmit: of wEmit:
genEmit(p, it) genEmit(p, it)
of wBreakpoint: of wBreakpoint:

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -10,21 +10,58 @@
# This module declares some helpers for the C code generator. # This module declares some helpers for the C code generator.
import import
ast, astalgo, ropes, lists, nhashes, strutils, types, msgs ast, astalgo, ropes, lists, nhashes, strutils, types, msgs, wordrecg,
platform
proc toCChar*(c: Char): string proc whichPragma*(n: PNode): TSpecialWord =
proc makeCString*(s: string): PRope var key = if n.kind == nkExprColonExpr: n.sons[0] else: n
proc makeLLVMString*(s: string): PRope if key.kind == nkIdent: result = whichKeyword(key.ident)
proc TableGetType*(tab: TIdTable, key: PType): PObject
proc GetUniqueType*(key: PType): PType proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
# implementation case n.kind
of nkStmtList:
for i in 0 .. < n.len:
result = getPragmaStmt(n[i], w)
if result != nil: break
of nkPragma:
for i in 0 .. < n.len:
if whichPragma(n[i]) == w: return n[i]
else: nil
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
result = getPragmaStmt(n, w) != nil
proc hashString*(s: string): biggestInt =
# has to be the same algorithm as system.hashString!
if CPU[targetCPU].bit == 64:
# we have to use the same bitwidth
# as the target CPU
var b = 0'i64
for i in countup(0, len(s) - 1):
b = b +% Ord(s[i])
b = b +% `shl`(b, 10)
b = b xor `shr`(b, 6)
b = b +% `shl`(b, 3)
b = b xor `shr`(b, 11)
b = b +% `shl`(b, 15)
result = b
else:
var a = 0'i32
for i in countup(0, len(s) - 1):
a = a +% Ord(s[i]).int32
a = a +% `shl`(a, 10'i32)
a = a xor `shr`(a, 6'i32)
a = a +% `shl`(a, 3'i32)
a = a xor `shr`(a, 11'i32)
a = a +% `shl`(a, 15'i32)
result = a
var gTypeTable: array[TTypeKind, TIdTable] var gTypeTable: array[TTypeKind, TIdTable]
proc initTypeTables() = proc initTypeTables() =
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i]) for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
proc GetUniqueType(key: PType): PType = proc GetUniqueType*(key: PType): PType =
var var
t: PType t: PType
k: TTypeKind k: TTypeKind
@ -32,33 +69,7 @@ proc GetUniqueType(key: PType): PType =
result = key result = key
if key == nil: return if key == nil: return
k = key.kind k = key.kind
case k # case k
# case key.Kind of
# tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
# tyInt..tyFloat128, tyProc, tyAnyEnum: begin end;
# tyNone, tyForward:
# InternalError('GetUniqueType: ' + typeToString(key));
# tyGenericParam, tyGeneric, tyAbstract, tySequence,
# tyOpenArray, tySet, tyVar, tyRef, tyPtr, tyArrayConstr,
# tyArray, tyTuple, tyRange: begin
# // we have to do a slow linear search because types may need
# // to be compared by their structure:
# if IdTableHasObjectAsKey(gTypeTable, key) then exit;
# for h := 0 to high(gTypeTable.data) do begin
# t := PType(gTypeTable.data[h].key);
# if (t <> nil) and sameType(t, key) then begin result := t; exit end
# end;
# IdTablePut(gTypeTable, key, key);
# end;
# tyObject, tyEnum: begin
# result := PType(IdTableGet(gTypeTable, key));
# if result = nil then begin
# IdTablePut(gTypeTable, key, key);
# result := key;
# end
# end;
# tyGenericInst, tyAbstract: result := GetUniqueType(lastSon(key));
# end;
of tyObject, tyEnum: of tyObject, tyEnum:
result = PType(IdTableGet(gTypeTable[k], key)) result = PType(IdTableGet(gTypeTable[k], key))
if result == nil: if result == nil:
@ -78,7 +89,7 @@ proc GetUniqueType(key: PType): PType =
return t return t
IdTablePut(gTypeTable[k], key, key) IdTablePut(gTypeTable[k], key, key)
proc TableGetType(tab: TIdTable, key: PType): PObject = proc TableGetType*(tab: TIdTable, key: PType): PObject =
var t: PType var t: PType
# returns nil if we need to declare this type # returns nil if we need to declare this type
result = IdTableGet(tab, key) result = IdTableGet(tab, key)
@ -91,13 +102,13 @@ proc TableGetType(tab: TIdTable, key: PType): PObject =
if sameType(t, key): if sameType(t, key):
return tab.data[h].val return tab.data[h].val
proc toCChar(c: Char): string = proc toCChar*(c: Char): string =
case c case c
of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c) of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
of '\'', '\"', '\\': result = '\\' & c of '\'', '\"', '\\': result = '\\' & c
else: result = $(c) else: result = $(c)
proc makeCString(s: string): PRope = proc makeCString*(s: string): PRope =
# BUGFIX: We have to split long strings into many ropes. Otherwise # BUGFIX: We have to split long strings into many ropes. Otherwise
# this could trigger an InternalError(). See the ropes module for # this could trigger an InternalError(). See the ropes module for
# further information. # further information.
@ -117,9 +128,8 @@ proc makeCString(s: string): PRope =
add(res, '\"') add(res, '\"')
app(result, toRope(res)) app(result, toRope(res))
proc makeLLVMString(s: string): PRope = proc makeLLVMString*(s: string): PRope =
const const MaxLineLength = 64
MaxLineLength = 64
var res: string var res: string
result = nil result = nil
res = "c\"" res = "c\""

View file

@ -308,12 +308,17 @@ proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
proc zeroTemp(p: BProc, loc: TLoc) = proc zeroTemp(p: BProc, loc: TLoc) =
if skipTypes(loc.t, abstractVarRange).Kind notin if skipTypes(loc.t, abstractVarRange).Kind notin
{tyArray, tyArrayConstr, tySet, tyTuple, tyObject}: {tyArray, tyArrayConstr, tySet, tyTuple, tyObject}:
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
when false:
var nilLoc: TLoc var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, onStack) initLoc(nilLoc, locTemp, loc.t, onStack)
nilLoc.r = toRope("NIM_NIL") nilLoc.r = toRope("NIM_NIL")
# puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``: # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
genRefAssign(p, loc, nilLoc, {afSrcIsNil}) genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else: else:
appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)])
when false:
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(loc), genTypeInfo(p.module, loc.t)]) [addrLoc(loc), genTypeInfo(p.module, loc.t)])

View file

@ -193,23 +193,23 @@ proc MainCommand(cmd, filename: string) =
setID(100) setID(100)
passes.gIncludeFile = syntaxes.parseFile passes.gIncludeFile = syntaxes.parseFile
passes.gImportModule = importModule passes.gImportModule = importModule
case whichKeyword(cmd) case cmd.normalize
of wCompile, wCompileToC, wC, wCC: of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently # compile means compileToC currently
gCmd = cmdCompileToC gCmd = cmdCompileToC
wantFile(filename) wantFile(filename)
CommandCompileToC(filename) CommandCompileToC(filename)
of wCompileToCpp: of "compiletocpp":
extccomp.cExt = ".cpp" extccomp.cExt = ".cpp"
gCmd = cmdCompileToCpp gCmd = cmdCompileToCpp
wantFile(filename) wantFile(filename)
CommandCompileToC(filename) CommandCompileToC(filename)
of wCompileToOC, wOC: of "oc", "compiletooc":
extccomp.cExt = ".m" extccomp.cExt = ".m"
gCmd = cmdCompileToOC gCmd = cmdCompileToOC
wantFile(filename) wantFile(filename)
CommandCompileToC(filename) CommandCompileToC(filename)
of wRun: of "run":
gCmd = cmdRun gCmd = cmdRun
wantFile(filename) wantFile(filename)
when hasTinyCBackend: when hasTinyCBackend:
@ -217,61 +217,61 @@ proc MainCommand(cmd, filename: string) =
CommandCompileToC(filename) CommandCompileToC(filename)
else: else:
rawMessage(errInvalidCommandX, cmd) rawMessage(errInvalidCommandX, cmd)
of wCompileToEcmaScript, wJs: of "js", "compiletoecmascript":
gCmd = cmdCompileToEcmaScript gCmd = cmdCompileToEcmaScript
wantFile(filename) wantFile(filename)
CommandCompileToEcmaScript(filename) CommandCompileToEcmaScript(filename)
of wCompileToLLVM: of "compiletollvm":
gCmd = cmdCompileToLLVM gCmd = cmdCompileToLLVM
wantFile(filename) wantFile(filename)
when has_LLVM_Backend: when has_LLVM_Backend:
CommandCompileToLLVM(filename) CommandCompileToLLVM(filename)
else: else:
rawMessage(errInvalidCommandX, cmd) rawMessage(errInvalidCommandX, cmd)
of wPretty: of "pretty":
gCmd = cmdPretty gCmd = cmdPretty
wantFile(filename) #CommandExportSymbols(filename); wantFile(filename) #CommandExportSymbols(filename);
CommandPretty(filename) CommandPretty(filename)
of wDoc: of "doc":
gCmd = cmdDoc gCmd = cmdDoc
LoadSpecialConfig(DocConfig) LoadSpecialConfig(DocConfig)
wantFile(filename) wantFile(filename)
CommandDoc(filename) CommandDoc(filename)
of wRst2html: of "rst2html":
gCmd = cmdRst2html gCmd = cmdRst2html
LoadSpecialConfig(DocConfig) LoadSpecialConfig(DocConfig)
wantFile(filename) wantFile(filename)
CommandRst2Html(filename) CommandRst2Html(filename)
of wRst2tex: of "rst2tex":
gCmd = cmdRst2tex gCmd = cmdRst2tex
LoadSpecialConfig(DocTexConfig) LoadSpecialConfig(DocTexConfig)
wantFile(filename) wantFile(filename)
CommandRst2TeX(filename) CommandRst2TeX(filename)
of wGenDepend: of "gendepend":
gCmd = cmdGenDepend gCmd = cmdGenDepend
wantFile(filename) wantFile(filename)
CommandGenDepend(filename) CommandGenDepend(filename)
of wDump: of "dump":
gCmd = cmdDump gCmd = cmdDump
condsyms.ListSymbols() condsyms.ListSymbols()
for it in iterSearchPath(): MsgWriteln(it) for it in iterSearchPath(): MsgWriteln(it)
of wCheck: of "check":
gCmd = cmdCheck gCmd = cmdCheck
wantFile(filename) wantFile(filename)
CommandCheck(filename) CommandCheck(filename)
of wParse: of "parse":
gCmd = cmdParse gCmd = cmdParse
wantFile(filename) wantFile(filename)
discard parseFile(addFileExt(filename, nimExt)) discard parseFile(addFileExt(filename, nimExt))
of wScan: of "scan":
gCmd = cmdScan gCmd = cmdScan
wantFile(filename) wantFile(filename)
CommandScan(filename) CommandScan(filename)
MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!") MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
of wI: of "i":
gCmd = cmdInteractive gCmd = cmdInteractive
CommandInteractive() CommandInteractive()
of wIdeTools: of "idetools":
gCmd = cmdIdeTools gCmd = cmdIdeTools
wantFile(filename) wantFile(filename)
CommandSuggest(filename) CommandSuggest(filename)

View file

@ -34,12 +34,12 @@ const
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal,
wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint,
wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks, wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
wInfChecks, wNanChecks, wPragma, wEmit} wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure,
wDeprecated, wExtern} wDeprecated, wExtern}
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern} wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern} wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern}
@ -357,6 +357,19 @@ proc PragmaEmit(c: PContext, n: PNode) =
proc noVal(n: PNode) = proc noVal(n: PNode) =
if n.kind == nkExprColonExpr: invalidPragma(n) if n.kind == nkExprColonExpr: invalidPragma(n)
proc PragmaUnroll(c: PContext, n: PNode) =
if c.p.nestedLoopCounter <= 0:
invalidPragma(n)
elif n.kind == nkExprColonExpr:
var unrollFactor = expectIntLit(c, n)
if unrollFactor <% 32:
n.sons[1] = newIntNode(nkIntLit, unrollFactor)
else:
invalidPragma(n)
proc PragmaLinearScanEnd(c: PContext, n: PNode) =
noVal(n)
proc processPragma(c: PContext, n: PNode, i: int) = proc processPragma(c: PContext, n: PNode, i: int) =
var it = n.sons[i] var it = n.sons[i]
if it.kind != nkExprColonExpr: invalidPragma(n) if it.kind != nkExprColonExpr: invalidPragma(n)
@ -475,6 +488,10 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
noVal(it) noVal(it)
if sym.typ == nil: invalidPragma(it) if sym.typ == nil: invalidPragma(it)
incl(sym.typ.flags, tfAcyclic) incl(sym.typ.flags, tfAcyclic)
of wShallow:
noVal(it)
if sym.typ == nil: invalidPragma(it)
incl(sym.typ.flags, tfShallow)
of wTypeCheck: of wTypeCheck:
noVal(it) noVal(it)
incl(sym.flags, sfTypeCheck) incl(sym.flags, sfTypeCheck)
@ -509,6 +526,8 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if sym.typ == nil: invalidPragma(it) if sym.typ == nil: invalidPragma(it)
sym.typ.callConv = wordToCallConv(k) sym.typ.callConv = wordToCallConv(k)
of wEmit: PragmaEmit(c, it) of wEmit: PragmaEmit(c, it)
of wUnroll: PragmaUnroll(c, it)
of wLinearScanEnd: PragmaLinearScanEnd(c, it)
else: invalidPragma(it) else: invalidPragma(it)
else: invalidPragma(it) else: invalidPragma(it)
else: processNote(c, it) else: processNote(c, it)

View file

@ -410,10 +410,13 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
proc semDirectCallAnalyseEffects(c: PContext, n: PNode, proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
flags: TExprFlags): PNode = flags: TExprFlags): PNode =
if not (efWantIterator in flags): var symflags = {skProc, skMethod, skConverter}
result = semDirectCall(c, n, {skProc, skMethod, skConverter}) if efWantIterator in flags:
else: symflags = {skIterator}
result = semDirectCall(c, n, {skIterator}) elif efAllowType in flags:
# for ``type countup(1,3)``, see ``tests/ttoseq``.
symflags.incl(skIterator)
result = semDirectCall(c, n, symflags)
if result != nil: if result != nil:
if result.sons[0].kind != nkSym: if result.sons[0].kind != nkSym:
InternalError("semDirectCallAnalyseEffects") InternalError("semDirectCallAnalyseEffects")
@ -1037,7 +1040,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of paNone: result = nil of paNone: result = nil
of paTuplePositions: result = semTuplePositionsConstr(c, n) of paTuplePositions: result = semTuplePositionsConstr(c, n)
of paTupleFields: result = semTupleFieldsConstr(c, n) of paTupleFields: result = semTupleFieldsConstr(c, n)
of paSingle: result = semExpr(c, n.sons[0]) of paSingle: result = semExpr(c, n.sons[0], flags)
of nkCurly: result = semSetConstr(c, n) of nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n) of nkBracket: result = semArrayConstr(c, n)
of nkLambda: result = semLambda(c, n) of nkLambda: result = semLambda(c, n)

View file

@ -574,7 +574,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
case n.kind case n.kind
of nkEmpty: nil of nkEmpty: nil
of nkTypeOfExpr: of nkTypeOfExpr:
result = semExprWithType(c, n, {efAllowType}).typ checkSonsLen(n, 1)
result = semExprWithType(c, n.sons[0], {efAllowType}).typ
of nkPar: of nkPar:
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
else: GlobalError(n.info, errTypeExpected) else: GlobalError(n.info, errTypeExpected)

View file

@ -340,10 +340,6 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
#result = newTransNode(n.sons[0]) #result = newTransNode(n.sons[0])
#result[1] = transform(c, m.sons[0]) #result[1] = transform(c, m.sons[0])
#if skipTypes(n.sons[0].typ, abstractVar).kind == tyOpenArray:
# debug(result.pnode)
# liMessage(n.info, warnUser,
# "nkPassAsOpenArray introduced here " & renderTree(n))
else: else:
result = transformSons(c, n) result = transformSons(c, n)
else: else:

View file

@ -53,12 +53,8 @@ type
wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH, wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH,
wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg, wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg,
wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar, wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar,
wAcyclic, wIndex, wAcyclic, wShallow, wUnroll, wLinearScanEnd,
wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM, wIndex,
wCompileToOC,
wPretty,
wDoc, wGenDepend, wDump, wCheck, wParse, wScan, wJs, wOC,
wRst2html, wRst2tex, wI,
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wThreads, wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wThreads,
wRecursivePath, wRecursivePath,
wStdout, wStdout,
@ -105,34 +101,26 @@ const
"cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v", "cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v",
"help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced", "help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced",
"skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints", "skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints",
"nomain", "subschar", "acyclic", "index", "nomain", "subschar", "acyclic", "shallow", "unroll", "linearscanend",
"compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm", "index",
"compiletooc",
"pretty", "doc", "gendepend", "dump", "check", "parse", "scan",
"js", "oc", "rst2html", "rst2tex", "i",
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit", "write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
"threads", "recursivepath", "threads", "recursivepath",
"stdout", "stdout",
"idetools", "suggest", "track", "def", "context"] "idetools", "suggest", "track", "def", "context"]
proc whichKeyword*(id: PIdent): TSpecialWord proc findStr*(a: openarray[string], s: string): int =
proc whichKeyword*(id: String): TSpecialWord
proc findStr*(a: openarray[string], s: string): int
# implementation
proc findStr(a: openarray[string], s: string): int =
for i in countup(low(a), high(a)): for i in countup(low(a), high(a)):
if cmpIgnoreStyle(a[i], s) == 0: if cmpIgnoreStyle(a[i], s) == 0:
return i return i
result = - 1 result = - 1
proc whichKeyword(id: String): TSpecialWord = proc whichKeyword*(id: PIdent): TSpecialWord =
result = whichKeyword(getIdent(id))
proc whichKeyword(id: PIdent): TSpecialWord =
if id.id < 0: result = wInvalid if id.id < 0: result = wInvalid
else: result = TSpecialWord(id.id) else: result = TSpecialWord(id.id)
proc whichKeyword*(id: String): TSpecialWord =
result = whichKeyword(getIdent(id))
proc initSpecials() = proc initSpecials() =
# initialize the keywords: # initialize the keywords:
for s in countup(succ(low(specialWords)), high(specialWords)): for s in countup(succ(low(specialWords)), high(specialWords)):

View file

@ -0,0 +1,11 @@
iterator fibonacci(): int =
var a = 0
var b = 1
while true:
yield a
var c = b
b = a
a = a + c

185
tests/accept/run/tsort.nim Normal file
View file

@ -0,0 +1,185 @@
# design criteria:
# Generic code is expenisve wrt code size!
# So the implementation should be small.
# The sort should be stable.
#
proc sort[T](arr: var openArray[T], lo, hi: natural) =
var k = 0
if lo < hi:
var mid = (lo + hi) div 2
sort(arr, lo, mid)
inc(mid)
sort(arr, mid, hi)
while lo < mid and mid <= hi:
if arr[lo] < arr[mid]:
inc(lo)
else:
when swapIsExpensive(T):
var help = arr[mid]
for k in countdown(mid, succ(lo)):
arr[k] = arr[pred(k)]
arr[lo] = help
else:
for k in countdown(mid, succ(lo)):
swap(arr[k], arr[pred(k)])
inc(lo)
inc(mid)
type
TSortOrder* = enum
Descending = -1,
Ascending = 0
proc flip(x: int, order: TSortOrder): int {.inline.} =
result = x xor ord(order) - ord(order)
# We use a fixed size stack. This size is larger
# than can be overflowed on a 64-bit machine
const
stackSize = 66
minRunSize = 7
type
TRun = tuple[index, length: int]
TSortState[T] {.pure, final.} = object
storage: seq[T]
runs: array[0..stackSize-1, TRun]
stackHeight: int # The index of the first unwritten element of the stack.
partitionedUpTo, length: int
# We keep track of how far we've partitioned up
# to so we know where to start the next partition.
# The idea is that everything < partionedUpTo
# is on the stack, everything >= partionedUpTo
# is not yet on the stack. When partitionedUpTo == length
# we'll have put everything on the stack.
proc reverse[T](a: var openArray[T], first, last: int) =
for j in first .. < first+length div 2: swap(a[j], a[length-j-1])
proc insertionSort[T]( int xs[], int length) =
for i in 1.. < length:
# The array before i is sorted. Now insert xs[i] into it
var x = xs[i]
var j = i-1
# Move j down until it's either at the beginning or on
# something <= x, and everything to the right of it has
# been moved up one.
while j >= 0 and xs[j] > x:
xs[j+1] = xs[j]
dec j
xs[j+1] = x
proc boostRunLength(s: TSortState, run: var TRun) =
# Need to make sure we don't overshoot the end of the array
var length = min(s.length - run.index, minRunSize)
insertionSort(run.index, length)
run.length = length
proc nextPartition[T](a: var openarray[T], s: var TSortState): bool =
if s.partitionedUpTo >= s.length: return false
var startIndex = s.partitionedUpTo
# Find an increasing run starting from startIndex
var nextStartIndex = startIndex + 1
if nextStartIndex < s.length:
if a[nextStartIndex] < a[startIndex]:
# We have a decreasing sequence starting here.
while nextStartIndex < s.length:
if a[nextStartIndex] < a[nextStartIndex-1]: inc(nextStartIndex)
else: break
# Now reverse it in place.
reverse(a, startIndex, nextStartIndex)
else:
# We have an increasing sequence starting here.
while nextStartIndex < s.length:
if a[nextStartIndex] >= a[nextStartIndex-1]: inc(nextStartIndex)
else: break
# So now [startIndex, nextStartIndex) is an increasing run.
# Push it onto the stack.
var runToAdd: TRun = (startIndex, nextStartIndex - startIndex)
if runToAdd.length < minRunSize:
boostRunLength(s, runToAdd)
s.partitionedUpTo = startIndex + runToAdd.length
s.runs[s.stackHeight] = runToAdd
inc s.stackHeight
result = true
proc shouldCollapse(s: TSortState): bool =
if s.stackHeight > 2:
var h = s.stackHeight-1
var headLength = s.runs[h].length
var nextLength = s.runs[h-1].length
result = 2 * headLength > nextLength
proc merge(int target[], int p1[], int l1, int p2[], int l2, int storage[]) =
# Merge the sorted arrays p1, p2 of length l1, l2 into a single
# sorted array starting at target. target may overlap with either
# of p1 or p2 but must have enough space to store the array.
# Use the storage argument for temporary storage. It must have room for
# l1 + l2 ints.
int *merge_to = storage
# Current index into each of the two arrays we're writing
# from.
int i1, i2;
i1 = i2 = 0;
# The address to which we write the next element in the merge
int *next_merge_element = merge_to;
# Iterate over the two arrays, writing the least element at the
# current position to merge_to. When the two are equal we prefer
# the left one, because if we're merging left, right we want to
# ensure stability.
# Of course this doesn't matter for integers, but it's the thought
# that counts.
while i1 < l1 and i2 < l2:
if p1[i1] <= p2[i2]:
*next_merge_element = p1[i1];
i1++
else:
*next_merge_element = p2[i2];
i2++
next_merge_element++
# If we stopped short before the end of one of the arrays
# we now copy the rest over.
memcpy(next_merge_element, p1 + i1, sizeof(int) * (l1 - i1));
memcpy(next_merge_element, p2 + i2, sizeof(int) * (l2 - i2));
# We've now merged into our additional working space. Time
# to copy to the target.
memcpy(target, merge_to, sizeof(int) * (l1 + l2));
proc mergeCollapse(a: s: var TSortState) =
var X = s.runs[s.stackHeight-2]
var Y = s.runs[s.stackHeight-1]
merge(X.index, X.index, X.length, Y.index, Y.length, s.storage)
dec s.stackHeight
inc X.length, Y.length
s.runs[s.stackHeight-1] = X
proc sort[T](arr: var openArray[T], first, last: natural,
cmp: proc (x,y: T): int, order = TSortOrder.ascending) =
var s: TSortState
newSeq(s.storage, arr.len)
s.stackHeight = 0
s.partitionedUpTo = 0
s.length = arr.len
while nextPartition(s):
while shouldCollapse(s): mergeCollapse(s)
while s.stackHeight > 1: mergeCollapse(s)
proc sort[T](arr: var openArray[T], cmp: proc (x, y: T): int = cmp,
order = TSortOrder.ascending) =
sort(arr, 0, high(arr), order)

View file

@ -0,0 +1,12 @@
discard """
output: "23456"
"""
template toSeq*(iter: expr): expr =
var result: seq[type(iter)] = @[]
for x in iter: add(result, x)
result
for x, y in items(toSeq(countup(2, 6))).withIndex:
stdout.write(x)

View file

@ -1,5 +1,4 @@
- 'nimrod def': does not always work - 'nimrod def': does not always work
- BUG: gcleak.nim
- thread support: threadvar on Windows seems broken; - thread support: threadvar on Windows seems broken;
add --deadlock_prevention:on|off switch add --deadlock_prevention:on|off switch

View file

@ -21,6 +21,7 @@ Bugfixes
copied. copied.
- Bugfix: The compiler does not emit very inaccurate floating point literals - Bugfix: The compiler does not emit very inaccurate floating point literals
anymore. anymore.
- Lots of other bugfixes: Too many to list them all.
Changes affecting backwards compatibility Changes affecting backwards compatibility
@ -65,6 +66,9 @@ Additions
- Added ``math.floor``. - Added ``math.floor``.
- The *interactive mode* (REPL) has been improved and documented for the - The *interactive mode* (REPL) has been improved and documented for the
first time. first time.
- Added the ``linearScanEnd`` and ``unroll`` pragmas.
- The compiler now might use a hashing for string case statements depending
on the number of string literals in the case statement.
2010-10-20 Version 0.8.10 released 2010-10-20 Version 0.8.10 released