mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-08 14:03:23 +00:00
better code generation for constant aggregates
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
8
todo.txt
8
todo.txt
@@ -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!
|
||||
|
||||
Reference in New Issue
Block a user