better code generation for constant aggregates
This commit is contained in:
parent
47f523cfb8
commit
351e89e705
10 changed files with 79 additions and 32 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
8
todo.txt
8
todo.txt
|
|
@ -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!
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue