better code generation for constant aggregates

This commit is contained in:
Araq
2011-11-02 00:55:29 +01:00
parent 47f523cfb8
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")
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 expr(p: BProc, e: PNode, d: var TLoc) =
case e.kind
@@ -1791,13 +1808,23 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
genNamedParamCall(p, e, d)
else:
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:
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)
else:
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 nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(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])])
data.app("}")
inc(p.labels)
result = con("CNSTSEQ", p.labels.toRope)
inc(gBackendId)
result = con("CNSTSEQ", gBackendId.toRope)
appcg(p.module, cfsData,
"NIM_CONST struct {$n" &
@@ -1872,7 +1899,6 @@ proc genConstExpr(p: BProc, n: PNode): PRope =
toBitSet(n, cs)
result = genRawSetData(cs, int(getSize(n.typ)))
of nkBracket, nkPar:
# XXX: tySequence!
var t = skipTypes(n.typ, abstractInst)
if t.kind == tySequence:
result = genConstSeq(p, n, t)

View File

@@ -67,7 +67,7 @@ proc genConstStmt(p: BProc, t: PNode) =
var c = it.sons[0].sym
if sfFakeConst in c.flags:
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:
# generate the data:
fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown)

View File

@@ -147,7 +147,8 @@ proc removeTrailingDirSep*(path: string): string =
result = path
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 =
## 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 opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
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)
addSon(a, opNode)
addSon(a, result)

View File

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

View File

@@ -657,6 +657,12 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
else:
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 =
case n.kind
of nkSym:
@@ -723,8 +729,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
result = transformSons(c, n)
var cnst = getConstExpr(c.module, PNode(result))
# we inline constants if they are not complex constants:
if cnst != nil and (cnst.kind notin {nkCurly, nkPar, nkBracket} or
cnst.len == 0):
if cnst != nil and not dontInlineConstant(n, cnst):
result = PTransNode(cnst) # do not miss an optimization
proc processTransf(context: PPassContext, n: PNode): PNode =

View File

@@ -108,6 +108,19 @@ proc isConstExpr*(n: PNode): bool =
{nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
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) =
if (getMagic(a) == op): # a is a "leaf", so add it:
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.
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
module.
@@ -558,8 +558,8 @@ caller, a ``var`` parameter can be used:
.. code-block:: nimrod
proc divmod(a, b: int, res, remainder: var int) =
res = a div b
remainder = a mod b
res = a div b # integer division
remainder = a mod b # integer modulo operation
var
x, y: int

View File

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

View File

@@ -1,6 +1,8 @@
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)
- fix actors.nim; test with different thread var implementations
- dead code elim for JS backend
@@ -10,6 +12,9 @@ Version 0.8.14
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
- 'let x = y'
- const ptr/ref
@@ -31,8 +36,6 @@ version 0.9.0
Bugs
----
- bug: s[1..n] = @[] produces wrong C code
- bug: template t(f_no_Type): stmt = ... crashes the compiler
- 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...
@@ -45,7 +48,6 @@ Bugs
var x: int
result = forward(x)
- bug: DLL generation is broken; write at least a basic test
- bug: stress testing basic method example (eval example)
without ``-d:release`` leaks memory; good way to figure out how a
fixed amount of stack can hold an arbitrary number of GC roots!