codegen uses alias analysis to generate better code

This commit is contained in:
Araq
2011-12-10 01:06:32 +01:00
parent 2962ca7890
commit af792da0bb
14 changed files with 166 additions and 113 deletions

View File

@@ -41,7 +41,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
result = arNo
if a == nil: return
if a == nil or b == nil: return
if ContainsOrIncl(marker, a.id): return
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
case a.kind

View File

@@ -155,9 +155,7 @@ proc SameValue*(a, b: PNode): bool =
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit:
if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
else:
debug a
debug b
else:
InternalError(a.info, "SameValue")
proc leValue*(a, b: PNode): bool =

View File

@@ -10,16 +10,30 @@
type
TAfterCallActions = tuple[p: BProc, actions: PRope]
proc fixupCall(p: BProc, t: PNode, d: var TLoc, pl: PRope) =
proc leftAppearsOnRightSide(le, ri: PNode): bool =
if le != nil:
for i in 1 .. <ri.len:
if le.isPartOf(ri[i]) != arNo: return true
proc hasNoInit(call: PNode): bool {.inline.} =
result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
proc resetLoc(p: BProc, d: var TLoc) =
zeroVar(p, d, containsGarbageCollectedRef(d.t))
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
var pl = pl
var typ = t.sons[0].typ # getUniqueType() is too expensive here!
var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
if sonsLen(t) > 1: app(pl, ", ")
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
if sonsLen(ri) > 1: app(pl, ", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
# Great, we can use 'd':
if d.k == locNone: getTemp(p, typ.sons[0], d)
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
resetLoc(p, d)
app(pl, addrLoc(d))
app(pl, ")")
app(p.s[cpsStmts], pl)
@@ -117,40 +131,40 @@ proc genArgNoParam(aca: var TAfterCallActions, n: PNode): PRope =
initLocExpr(aca.p, n, a)
result = rdLoc(a)
proc genCall(p: BProc, t: PNode, d: var TLoc) =
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
var aca: TAfterCallActions
aca.p = p
# this is a hotspot in the compiler
initLocExpr(p, t.sons[0], op)
initLocExpr(p, ri.sons[0], op)
var pl = con(op.r, "(")
var typ = t.sons[0].typ # getUniqueType() is too expensive here!
var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
assert(typ.kind == tyProc)
var length = sonsLen(t)
var length = sonsLen(ri)
for i in countup(1, length - 1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym)
app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym))
app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym))
else:
app(pl, genArgNoParam(aca, t.sons[i]))
app(pl, genArgNoParam(aca, ri.sons[i]))
if i < length - 1: app(pl, ", ")
fixupCall(p, t, d, pl)
fixupCall(p, le, ri, d, pl)
emitAfterCallActions(aca)
proc genInfixCall(p: BProc, t: PNode, d: var TLoc) =
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op, a: TLoc
var aca: TAfterCallActions
aca.p = p
initLocExpr(p, t.sons[0], op)
initLocExpr(p, ri.sons[0], op)
var pl: PRope = nil
var typ = t.sons[0].typ # getUniqueType() is too expensive here!
var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
assert(typ.kind == tyProc)
var length = sonsLen(t)
var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n))
var param = typ.n.sons[1].sym
app(pl, genArg(aca, t.sons[1], param))
app(pl, genArg(aca, ri.sons[1], param))
if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, "->")
else: app(pl, ".")
@@ -160,45 +174,45 @@ proc genInfixCall(p: BProc, t: PNode, d: var TLoc) =
assert(sonsLen(typ) == sonsLen(typ.n))
if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym)
app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym))
app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym))
else:
app(pl, genArgNoParam(aca, t.sons[i]))
app(pl, genArgNoParam(aca, ri.sons[i]))
if i < length - 1: app(pl, ", ")
fixupCall(p, t, d, pl)
fixupCall(p, le, ri, d, pl)
emitAfterCallActions(aca)
proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) =
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# generates a crappy ObjC call
var op, a: TLoc
var aca: TAfterCallActions
aca.p = p
initLocExpr(p, t.sons[0], op)
initLocExpr(p, ri.sons[0], op)
var pl = toRope"["
var typ = t.sons[0].typ # getUniqueType() is too expensive here!
var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
assert(typ.kind == tyProc)
var length = sonsLen(t)
var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n))
if length > 1:
app(pl, genArg(aca, t.sons[1], typ.n.sons[1].sym))
app(pl, genArg(aca, ri.sons[1], typ.n.sons[1].sym))
app(pl, " ")
app(pl, op.r)
if length > 2:
app(pl, ": ")
app(pl, genArg(aca, t.sons[2], typ.n.sons[2].sym))
app(pl, genArg(aca, ri.sons[2], typ.n.sons[2].sym))
for i in countup(3, length-1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ):
InternalError(t.info, "varargs for objective C method?")
InternalError(ri.info, "varargs for objective C method?")
assert(typ.n.sons[i].kind == nkSym)
var param = typ.n.sons[i].sym
app(pl, " ")
app(pl, param.name.s)
app(pl, ": ")
app(pl, genArg(aca, t.sons[i], param))
app(pl, genArg(aca, ri.sons[i], param))
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
if sonsLen(t) > 1: app(pl, " ")
if sonsLen(ri) > 1: app(pl, " ")
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
@@ -230,3 +244,21 @@ proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) =
appf(p.s[cpsStmts], ";$n")
emitAfterCallActions(aca)
proc genCall(p: BProc, e: PNode, d: var TLoc) =
if e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
e.len >= 2:
genInfixCall(p, nil, e, d)
elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
genNamedParamCall(p, e, d)
else:
genPrefixCall(p, nil, e, d)
proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
if ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and
ri.len >= 2:
genInfixCall(p, le, ri, d)
elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
genNamedParamCall(p, ri, d)
else:
genPrefixCall(p, le, ri, d)

View File

@@ -1628,11 +1628,6 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
nkCallStrLit:
if e.sons[0].kind == nkSym and e.sons[0].sym.magic != mNone:
genMagicExpr(p, e, d, e.sons[0].sym.magic)
elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
e.len >= 2:
genInfixCall(p, e, d)
elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
genNamedParamCall(p, e, d)
else:
genCall(p, e, d)
of nkCurly:

View File

@@ -18,16 +18,16 @@ proc genVarTuple(p: BProc, n: PNode) =
if n.kind != nkVarTuple: InternalError(n.info, "genVarTuple")
var L = sonsLen(n)
genLineDir(p, n)
initLocExpr(p, n.sons[L - 1], tup)
initLocExpr(p, n.sons[L-1], tup)
var t = tup.t
for i in countup(0, L - 3):
for i in countup(0, L-3):
var v = n.sons[i].sym
if sfGlobal in v.flags:
assignGlobalVar(p, v)
genObjectInit(p, cpsInit, v.typ, v.loc, true)
else:
else:
assignLocalVar(p, v)
initVariable(p, v)
initLocalVar(p, v, immediateAsgn=true)
initLoc(field, locExpr, t.sons[i], tup.s)
if t.n == nil:
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
@@ -37,17 +37,25 @@ proc genVarTuple(p: BProc, n: PNode) =
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
putLocIntoDest(p, v.loc, field)
proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
ri.sons[0].sym.magic == mNone):
genAsgnCall(p, le, ri, a)
else:
expr(p, ri, a)
proc genSingleVar(p: BProc, a: PNode) =
var v = a.sons[0].sym
var immediateAsgn = a.sons[2].kind != nkEmpty
if sfGlobal in v.flags:
assignGlobalVar(p, v)
genObjectInit(p, cpsInit, v.typ, v.loc, true)
else:
else:
assignLocalVar(p, v)
initVariable(p, v)
if a.sons[2].kind != nkEmpty:
initLocalVar(p, v, immediateAsgn)
if immediateAsgn:
genLineDir(p, a)
expr(p, a.sons[2], v.loc)
loadInto(p, a.sons[0], a.sons[2], v.loc)
proc genVarStmt(p: BProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
@@ -658,7 +666,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
InitLocExpr(p, e.sons[0], a)
if fastAsgn: incl(a.flags, lfNoDeepCopy)
assert(a.t != nil)
expr(p, e.sons[1], a)
loadInto(p, e.sons[0], e.sons[1], a)
else:
asgnFieldDiscriminant(p, e)

View File

@@ -14,7 +14,7 @@ import
options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
rodutils, renderer, idgen, cgendata, ccgmerge, semfold
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases
when options.hasTinyCBackend:
import tccgen
@@ -235,16 +235,17 @@ proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else:
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
else:
else:
if containsGcref and p.WithInLoop > 0:
appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)])
genObjectInit(p, cpsInit, loc.t, loc, true)
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(loc), genTypeInfo(p.module, loc.t)])
else:
appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)])
genObjectInit(p, cpsInit, loc.t, loc, true)
genObjectInit(p, cpsStmts, loc.t, loc, true)
proc zeroTemp(p: BProc, loc: TLoc) =
if skipTypes(loc.t, abstractVarRange).Kind notin
@@ -259,15 +260,22 @@ proc zeroTemp(p: BProc, loc: TLoc) =
else:
appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)])
# XXX no object init necessary for temporaries?
when false:
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(loc), genTypeInfo(p.module, loc.t)])
proc initVariable(p: BProc, v: PSym) =
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if sfNoInit notin v.flags:
var b = containsGarbageCollectedRef(v.typ)
if b or v.ast == nil:
zeroVar(p, v.loc, b)
# we know it is a local variable and thus on the stack!
# If ``not immediateAsgn`` it is not initialized in a binding like
# ``var v = X`` and thus we need to init it.
# If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow
# which requires initialization. However this can really only happen if
# ``var v = X()`` gets transformed into ``X(&v)``.
# Nowadays the logic in ccgcalls deals with this case however.
if not immediateAsgn:
zeroVar(p, v.loc, containsGarbageCollectedRef(v.typ))
proc initTemp(p: BProc, tmp: var TLoc) =
if containsGarbageCollectedRef(tmp.t) or isInvalidReturnType(tmp.t):
@@ -534,13 +542,14 @@ proc genProcAux(m: BModule, prc: PSym) =
assert(prc.ast != nil)
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
var res = prc.ast.sons[resultPos].sym # get result symbol
if not isInvalidReturnType(prc.typ.sons[0]):
if not isInvalidReturnType(prc.typ.sons[0]):
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
# declare the result symbol:
assignLocalVar(p, res)
assert(res.loc.r != nil)
returnStmt = ropeff("return $1;$n", "ret $1$n", [rdLoc(res.loc)])
initVariable(p, res)
else:
initLocalVar(p, res, immediateAsgn=false)
else:
fillResult(res)
assignParam(p, res)
if skipTypes(res.typ, abstractInst).kind == tyArray:

View File

@@ -23,7 +23,7 @@ const
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wNoStackFrame, wError, wDiscardable}
wNoStackFrame, wError, wDiscardable, wNoInit}
converterPragmas* = procPragmas
methodPragmas* = procPragmas
macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,

View File

@@ -983,12 +983,6 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
else:
result = semDirectOp(c, n, flags)
of mExpandToAst: result = semExpandToAst(c, n, s, flags)
of mAstToStr:
if sonsLen(n) == 2:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
result.typ = getSysType(tyString)
else:
result = semDirectOp(c, n, flags)
else: result = semDirectOp(c, n, flags)
proc semIfExpr(c: PContext, n: PNode): PNode =

View File

@@ -31,6 +31,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
case n[0].sym.magic
of mSlurp: result = semSlurp(c, n, flags)
of mIsPartOf: result = semIsPartOf(c, n, flags)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
result.typ = getSysType(tyString)
else: result = n

View File

@@ -1584,6 +1584,11 @@ The implicit initialization can be avoided for optimization reasons with the
var
a {.noInit.}: array [0..1023, char]
If a proc is annotated with the ``noinit`` pragma this refers to its implicit
``result`` variable:
.. code-block:: nimrod
proc returnUndefinedValue: int {.noinit.} = nil
let statement
@@ -2849,6 +2854,7 @@ exported.
The algorithm for compiling modules is:
- compile the whole module as usual, following import statements recursively
- if there is a cycle only import the already parsed symbols (that are
exported); if an unknown identifier occurs then abort

View File

@@ -2071,14 +2071,24 @@ proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
## converts the AST of `x` into a string representation. This is very useful
## for debugging.
proc raiseAssert(msg: string) {.noinline.} =
raise newException(EAssertionFailed, msg)
template assert*(cond: expr, msg = "") =
## provides a means to implement `programming by contracts`:idx: in Nimrod.
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
## raises an ``EAssertionFailure`` exception. However, the compiler may
## not generate any code at all for ``assert`` if it is advised to do so.
## Use ``assert`` for debugging purposes only.
bind raiseAssert
when compileOption("assertions"):
if not cond:
raise newException(EAssertionFailed, astToStr(cond) & ' ' & msg)
raiseAssert(astToStr(cond) & ' ' & msg)
template doAssert*(cond: expr, msg = "") =
## same as `assert' but is always turned on and not affected by the
## ``--assertions`` command line switch.
bind raiseAssert
if not cond:
raiseAssert(astToStr(cond) & ' ' & msg)

View File

@@ -1669,25 +1669,25 @@ proc escapePeg*(s: string): string =
if inQuote: result.add('\'')
when isMainModule:
assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
#assert match("(a b c)", peg"'(' @ ')'")
assert match("W_HI_Le", peg"\y 'while'")
assert(not match("W_HI_L", peg"\y 'while'"))
assert(not match("W_HI_Le", peg"\y v'while'"))
assert match("W_HI_Le", peg"y'while'")
doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
#doAssert match("(a b c)", peg"'(' @ ')'")
doAssert match("W_HI_Le", peg"\y 'while'")
doAssert(not match("W_HI_L", peg"\y 'while'"))
doAssert(not match("W_HI_Le", peg"\y v'while'"))
doAssert match("W_HI_Le", peg"y'while'")
assert($ +digits == $peg"\d+")
assert "0158787".match(peg"\d+")
assert "ABC 0232".match(peg"\w+\s+\d+")
assert "ABC".match(peg"\d+ / \w+")
doAssert($ +digits == $peg"\d+")
doAssert "0158787".match(peg"\d+")
doAssert "ABC 0232".match(peg"\w+\s+\d+")
doAssert "ABC".match(peg"\d+ / \w+")
for word in split("00232this02939is39an22example111", peg"\d+"):
writeln(stdout, word)
assert matchLen("key", ident) == 3
doAssert matchLen("key", ident) == 3
var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
assert matchLen("key1= cal9", pattern) == 11
doAssert matchLen("key1= cal9", pattern) == 11
var ws = newNonTerminal("ws", 1, 1)
ws.rule = *whitespace
@@ -1698,24 +1698,24 @@ when isMainModule:
var c: TCaptures
var s = "a+b + c +d+e+f"
assert rawMatch(s, expr.rule, 0, c) == len(s)
doAssert rawMatch(s, expr.rule, 0, c) == len(s)
var a = ""
for i in 0..c.ml-1:
a.add(substr(s, c.matches[i][0], c.matches[i][1]))
assert a == "abcdef"
doAssert a == "abcdef"
#echo expr.rule
#const filename = "lib/devel/peg/grammar.txt"
#var grammar = parsePeg(newFileStream(filename, fmRead), filename)
#echo "a <- [abc]*?".match(grammar)
assert find("_____abc_______", term("abc"), 2) == 5
assert match("_______ana", peg"A <- 'ana' / . A")
assert match("abcs%%%", peg"A <- ..A / .A / '%'")
doAssert find("_____abc_______", term("abc"), 2) == 5
doAssert match("_______ana", peg"A <- 'ana' / . A")
doAssert match("abcs%%%", peg"A <- ..A / .A / '%'")
if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
assert matches[0] == "abc"
doAssert matches[0] == "abc"
else:
assert false
doAssert false
var g2 = peg"""S <- A B / C D
A <- 'a'+
@@ -1723,44 +1723,44 @@ when isMainModule:
C <- 'c'+
D <- 'd'+
"""
assert($g2 == "((A B) / (C D))")
assert match("cccccdddddd", g2)
assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
doAssert($g2 == "((A B) / (C D))")
doAssert match("cccccdddddd", g2)
doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
"var1<-keykey; var2<-key2key2")
assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
assert matches[0] == "a"
doAssert matches[0] == "a"
else:
assert false
doAssert false
var matches: array[0..5, string]
if match("abcdefg", peg"c {d} ef {g}", matches, 2):
assert matches[0] == "d"
assert matches[1] == "g"
doAssert matches[0] == "d"
doAssert matches[1] == "g"
else:
assert false
doAssert false
for x in findAll("abcdef", peg"{.}", 3):
echo x
if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
assert matches[0] == "f"
assert matches[1] == "a, b"
doAssert matches[0] == "f"
doAssert matches[1] == "a, b"
else:
assert false
doAssert false
assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+")
# ß is not a lower cased letter?!
assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
assert(not match("456678", peg"(\letter)+"))
doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+")
doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
doAssert(not match("456678", peg"(\letter)+"))
assert("var1 = key; var2 = key2".replacef(
doAssert("var1 = key; var2 = key2".replacef(
peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
"var1<-keykey;var2<-key2key2")
assert match("prefix/start", peg"^start$", 7)
doAssert match("prefix/start", peg"^start$", 7)
# tricky test to check for false aliasing:
block:

View File

@@ -1,7 +1,8 @@
version 0.8.14
==============
- find a proper bugfix for C compilers optimizing away stack roots
- implement a proper bugfix for C compilers optimizing away stack roots
- cleanup file path handling in the compiler
- warning for implicit openArray -> varargs convention
- implement explicit varargs; **but** ``len(varargs)`` problem remains!
@@ -37,9 +38,6 @@ version 0.9.0
Bugs
----
- bug: generic assign still buggy
- Optimization: If we use a temporary for the result anyway the code gen
should make use of this fact to generate better code...
- bug: memset() without type field initialization?
- special case the generic assign that needs to care about case objects
- bug: returning a tyVar does not mean it is save to return it:

View File

@@ -29,7 +29,7 @@ Changes affecting backwards compatibility
``os.iterOverEnvironment``, ``os.pcDirectory``, ``os.pcLinkToDirectory``,
``os.SplitPath``, ``os.extractDir``, ``os.SplitFilename``,
``os.extractFileTrunk``, ``os.extractFileExt``, ``osproc.executeProcess``,
``osproc.executeCommand``.
``osproc.executeCommand``.
- Removed deprecated ``parseopt.init``, ``parseopt.getRestOfCommandLine``.
- Moved ``strutils.validEmailAddress`` to ``matchers.validEmailAddress``.
- The pointer dereference operator ``^`` has been removed, so that ``^``
@@ -53,8 +53,8 @@ Changes affecting backwards compatibility
because they should not be used directly anymore.
Wrapper procs have been created that should be used instead.
- ``export`` is now a keyword.
- ``assert`` is now implemented in pure Nimrod; it's easy to implement your
own assertion schemes now.
- ``assert`` is now implemented in pure Nimrod as a template; it's easy
to implement your own assertion templates with ``system.astToStr``.
Language Additions
@@ -112,6 +112,7 @@ Compiler Additions
- Added ``--import:file`` and ``--include:file`` configuration options
for specifying modules that will be automatically imported/incluced.
- ``nimrod i`` can now optionally be given a module to execute.
- The compiler now performs a simple aliases analysis to generate better code.
Library Additions
@@ -128,7 +129,7 @@ Library Additions
- Added ``system.program_result``.
- Added ``xmltree.innerText``.
- Added ``os.isAbsolute``, ``os.dynLibFormat``, ``os.isRootDir``,
``os.parentDirs``.
``os.parentDirs``.
- Added ``parseutils.interpolatedFragments``.
- Added ``macros.treeRepr``, ``macros.lispRepr``, ``macros.dumpTree``,
``macros.dumpLisp``, ``macros.parseExpr``, ``macros.parseStmt``,
@@ -142,7 +143,7 @@ Library Additions
and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to
the old implementation.
- Added ``intsets.assign``.
- Added ``system.astToStr`` and ``system.rand``.
- Added ``system.astToStr`` and ``system.rand``, ``system.doAssert``.
2011-07-10 Version 0.8.12 released