better code generation for constant aggregates

This commit is contained in:
Araq 2011-11-02 00:55:29 +01:00
commit 351e89e705
10 changed files with 79 additions and 32 deletions

View file

@ -1727,6 +1727,23 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
for i in countup(1, abs(inheritanceDiff(dest, src))): app(r, ".Sup") for i in countup(1, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
putIntoDest(p, d, n.typ, r) putIntoDest(p, d, n.typ, r)
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var tmp = con("TMP", toRope(id))
if id == gBackendId:
# expression not found in the cache:
inc(gBackendId)
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
if d.k == locNone:
fillLoc(d, locData, t, tmp, OnHeap)
else:
putIntoDest(p, d, t, tmp)
proc genBlock(p: BProc, t: PNode, d: var TLoc) proc genBlock(p: BProc, t: PNode, d: var TLoc)
proc expr(p: BProc, e: PNode, d: var TLoc) = proc expr(p: BProc, e: PNode, d: var TLoc) =
case e.kind case e.kind
@ -1791,13 +1808,23 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
genNamedParamCall(p, e, d) genNamedParamCall(p, e, d)
else: else:
genCall(p, e, d) genCall(p, e, d)
of nkCurly: genSetConstr(p, e, d) of nkCurly:
if isDeepConstExpr(e) and e.len != 0:
putIntoDest(p, d, e.typ, genSetNode(p, e))
else:
genSetConstr(p, e, d)
of nkBracket: of nkBracket:
if skipTypes(e.typ, abstractVarRange).kind == tySequence: if isDeepConstExpr(e) and e.len != 0:
exprComplexConst(p, e, d)
elif skipTypes(e.typ, abstractVarRange).kind == tySequence:
genSeqConstr(p, e, d) genSeqConstr(p, e, d)
else: else:
genArrayConstr(p, e, d) genArrayConstr(p, e, d)
of nkPar: genTupleConstr(p, e, d) of nkPar:
if isDeepConstExpr(e) and e.len != 0:
exprComplexConst(p, e, d)
else:
genTupleConstr(p, e, d)
of nkCast: genCast(p, e, d) of nkCast: genCast(p, e, d)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d)
of nkHiddenAddr, nkAddr: genAddr(p, e, d) of nkHiddenAddr, nkAddr: genAddr(p, e, d)
@ -1851,8 +1878,8 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): PRope =
appf(data, ",$1$n", [genConstExpr(p, n.sons[i])]) appf(data, ",$1$n", [genConstExpr(p, n.sons[i])])
data.app("}") data.app("}")
inc(p.labels) inc(gBackendId)
result = con("CNSTSEQ", p.labels.toRope) result = con("CNSTSEQ", gBackendId.toRope)
appcg(p.module, cfsData, appcg(p.module, cfsData,
"NIM_CONST struct {$n" & "NIM_CONST struct {$n" &
@ -1872,7 +1899,6 @@ proc genConstExpr(p: BProc, n: PNode): PRope =
toBitSet(n, cs) toBitSet(n, cs)
result = genRawSetData(cs, int(getSize(n.typ))) result = genRawSetData(cs, int(getSize(n.typ)))
of nkBracket, nkPar: of nkBracket, nkPar:
# XXX: tySequence!
var t = skipTypes(n.typ, abstractInst) var t = skipTypes(n.typ, abstractInst)
if t.kind == tySequence: if t.kind == tySequence:
result = genConstSeq(p, n, t) result = genConstSeq(p, n, t)

View file

@ -67,7 +67,7 @@ proc genConstStmt(p: BProc, t: PNode) =
var c = it.sons[0].sym var c = it.sons[0].sym
if sfFakeConst in c.flags: if sfFakeConst in c.flags:
genSingleVar(p, it) genSingleVar(p, it)
elif c.typ.kind in ConstantDataTypes and not (lfNoDecl in c.loc.flags) and elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
c.ast.len != 0: c.ast.len != 0:
# generate the data: # generate the data:
fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown) fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown)

View file

@ -147,7 +147,8 @@ proc removeTrailingDirSep*(path: string): string =
result = path result = path
proc getGeneratedPath: string = proc getGeneratedPath: string =
result = if nimcacheDir.len > 0: nimcacheDir else: projectPath / genSubDir result = if nimcacheDir.len > 0: nimcacheDir else: projectPath.shortenDir /
genSubDir
proc toGeneratedFile*(path, ext: string): string = proc toGeneratedFile*(path, ext: string): string =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod" ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"

View file

@ -474,7 +474,8 @@ proc lowestExprAux(p: var TParser, limit: int): PNode =
var a = newNodeP(nkInfix, p) var a = newNodeP(nkInfix, p)
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator: var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
getTok(p) getTok(p)
optInd(p, opNode) # read sub-expression with higher priority optInd(p, opNode)
# read sub-expression with higher priority:
var b = lowestExprAux(p, opPrec + leftAssoc) var b = lowestExprAux(p, opPrec + leftAssoc)
addSon(a, opNode) addSon(a, opNode)
addSon(a, result) addSon(a, result)

View file

@ -261,7 +261,7 @@ proc changeType(n: PNode, newType: PType) =
if newType.kind != tyTuple: if newType.kind != tyTuple:
InternalError(n.info, "changeType: no tuple type for constructor") InternalError(n.info, "changeType: no tuple type for constructor")
if newType.n == nil: nil if newType.n == nil: nil
elif (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr): elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i].sons[0] var m = n.sons[i].sons[0]
if m.kind != nkSym: if m.kind != nkSym:
@ -314,6 +314,7 @@ proc semArrayConstr(c: PContext, n: PNode): PNode =
result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info) result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info)
proc fixAbstractType(c: PContext, n: PNode) = proc fixAbstractType(c: PContext, n: PNode) =
# XXX finally rewrite that crap!
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
case it.kind case it.kind
@ -909,10 +910,8 @@ proc expectStringArg(c: PContext, n: PNode, i: int): PNode =
if result.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}: if result.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
GlobalError(result.info, errStringLiteralExpected) GlobalError(result.info, errStringLiteralExpected)
proc isAstValue(n: PNode): bool = proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
result = n.typ.sym.name.s in [ "expr", "stmt", "PNimrodNode" ] flags: TExprFlags): PNode =
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, flags: TExprFlags): PNode =
if sonsLen(n) == 2: if sonsLen(n) == 2:
if not isCallExpr(n.sons[1]): if not isCallExpr(n.sons[1]):
GlobalError(n.info, errXisNoMacroOrTemplate, n.renderTree) GlobalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
@ -921,16 +920,16 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, flags: TExprFlags): P
var expandedSym = qualifiedLookup(c, macroCall.sons[0], {checkUndeclared}) var expandedSym = qualifiedLookup(c, macroCall.sons[0], {checkUndeclared})
if expandedSym == nil: if expandedSym == nil:
GlobalError(n.info, errUndeclaredIdentifier, macroCall.sons[0].renderTree) GlobalError(n.info, errUndeclaredIdentifier, macroCall[0].renderTree)
if not (expandedSym.kind in { skMacro, skTemplate }): if expandedSym.kind notin {skMacro, skTemplate}:
GlobalError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s) GlobalError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s)
macroCall.sons[0] = newNodeI(nkSym, macroCall.info) macroCall.sons[0] = newNodeI(nkSym, macroCall.info)
macroCall.sons[0].sym = expandedSym macroCall.sons[0].sym = expandedSym
markUsed(n, expandedSym) markUsed(n, expandedSym)
for i in countup(1, macroCall.sonsLen - 1): for i in countup(1, macroCall.len-1):
macroCall.sons[i] = semExprWithType(c, macroCall.sons[i], {efAllowType}) macroCall.sons[i] = semExprWithType(c, macroCall.sons[i], {efAllowType})
# Preserve the magic symbol in order to handled in evals.nim # Preserve the magic symbol in order to handled in evals.nim
@ -938,7 +937,6 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, flags: TExprFlags): P
n.sons[0].sym = magicSym n.sons[0].sym = magicSym
n.typ = expandedSym.getReturnType n.typ = expandedSym.getReturnType
result = n result = n
else: else:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)

View file

@ -657,6 +657,12 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
else: else:
result = transformSons(c, n) result = transformSons(c, n)
proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
# symbols that expand to a complex constant (array, etc.) should not be
# inlined, unless it's the empty array:
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
cnst.len != 0
proc transform(c: PTransf, n: PNode): PTransNode = proc transform(c: PTransf, n: PNode): PTransNode =
case n.kind case n.kind
of nkSym: of nkSym:
@ -723,8 +729,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
result = transformSons(c, n) result = transformSons(c, n)
var cnst = getConstExpr(c.module, PNode(result)) var cnst = getConstExpr(c.module, PNode(result))
# we inline constants if they are not complex constants: # we inline constants if they are not complex constants:
if cnst != nil and (cnst.kind notin {nkCurly, nkPar, nkBracket} or if cnst != nil and not dontInlineConstant(n, cnst):
cnst.len == 0):
result = PTransNode(cnst) # do not miss an optimization result = PTransNode(cnst) # do not miss an optimization
proc processTransf(context: PPassContext, n: PNode): PNode = proc processTransf(context: PPassContext, n: PNode): PNode =

View file

@ -108,6 +108,19 @@ proc isConstExpr*(n: PNode): bool =
{nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags) nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
proc isDeepConstExpr*(n: PNode): bool =
case n.kind
of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkNilLit:
result = true
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
result = isDeepConstExpr(n.sons[1])
of nkCurly, nkBracket, nkPar:
for i in 0 .. <n.len:
if not isDeepConstExpr(n.sons[i]): return false
result = true
else: nil
proc flattenTreeAux(d, a: PNode, op: TMagic) = proc flattenTreeAux(d, a: PNode, op: TMagic) =
if (getMagic(a) == op): # a is a "leaf", so add it: if (getMagic(a) == op): # a is a "leaf", so add it:
for i in countup(1, sonsLen(a) - 1): # BUGFIX for i in countup(1, sonsLen(a) - 1): # BUGFIX

View file

@ -76,7 +76,7 @@ Note that this is basically the only form of type inference that exists in
Nimrod: it is a good compromise between brevity and readability. Nimrod: it is a good compromise between brevity and readability.
The "hello world" program contains several identifiers that are already The "hello world" program contains several identifiers that are already
known to the compiler: ``echo``, ``readLine``, etc. These built-in items are known to the compiler: ``echo``, ``readLine``, etc. These built-ins are
declared in the system_ module which is implicitly imported by any other declared in the system_ module which is implicitly imported by any other
module. module.
@ -558,8 +558,8 @@ caller, a ``var`` parameter can be used:
.. code-block:: nimrod .. code-block:: nimrod
proc divmod(a, b: int, res, remainder: var int) = proc divmod(a, b: int, res, remainder: var int) =
res = a div b res = a div b # integer division
remainder = a mod b remainder = a mod b # integer modulo operation
var var
x, y: int x, y: int

View file

@ -63,10 +63,11 @@ type
region: TMemRegion # garbage collected region region: TMemRegion # garbage collected region
stat: TGcStat stat: TGcStat
var when not defined(useNimRtl):
var
gch {.rtlThreadVar.}: TGcHeap gch {.rtlThreadVar.}: TGcHeap
InstantiateForRegion(gch.region) InstantiateForRegion(gch.region)
proc acquire(gch: var TGcHeap) {.inline.} = proc acquire(gch: var TGcHeap) {.inline.} =
when hasThreadSupport and hasSharedHeap: when hasThreadSupport and hasSharedHeap:

View file

@ -1,6 +1,8 @@
Version 0.8.14 Version 0.8.14
============== ==============
- bug: s[1..n] = @[] produces wrong C code
- bug: DLL generation is broken; write at least a basic test
- optimize unused constants away (affected by HLO) - optimize unused constants away (affected by HLO)
- fix actors.nim; test with different thread var implementations - fix actors.nim; test with different thread var implementations
- dead code elim for JS backend - dead code elim for JS backend
@ -10,6 +12,9 @@ Version 0.8.14
version 0.9.0 version 0.9.0
============= =============
- special precedence rules for assignment operators: If the operator ends with
'=' and does **not** start with '<', '>', '!', '=', '~', '?', it is an
assignment operator
- test the sort implementation again - test the sort implementation again
- 'let x = y' - 'let x = y'
- const ptr/ref - const ptr/ref
@ -31,8 +36,6 @@ version 0.9.0
Bugs Bugs
---- ----
- bug: s[1..n] = @[] produces wrong C code
- bug: template t(f_no_Type): stmt = ... crashes the compiler
- bug: generic assign still buggy - bug: generic assign still buggy
- Optimization: If we use a temporary for the result anyway the code gen - Optimization: If we use a temporary for the result anyway the code gen
should make use of this fact to generate better code... should make use of this fact to generate better code...
@ -45,7 +48,6 @@ Bugs
var x: int var x: int
result = forward(x) result = forward(x)
- bug: DLL generation is broken; write at least a basic test
- bug: stress testing basic method example (eval example) - bug: stress testing basic method example (eval example)
without ``-d:release`` leaks memory; good way to figure out how a without ``-d:release`` leaks memory; good way to figure out how a
fixed amount of stack can hold an arbitrary number of GC roots! fixed amount of stack can hold an arbitrary number of GC roots!