constant folding for cnst[i] and cnst.attr

This commit is contained in:
Araq 2011-10-29 23:54:50 +02:00
commit 299390a585
5 changed files with 78 additions and 49 deletions

View file

@ -281,7 +281,9 @@ type
nfBase2, # nfBase10 is default, so not needed nfBase2, # nfBase10 is default, so not needed
nfBase8, nfBase8,
nfBase16, nfBase16,
nfAllConst, # used to mark complex expressions constant nfAllConst, # used to mark complex expressions constant; easy to get rid of
# but unfortunately it has measurable impact for compilation
# efficiency
nfTransf, # node has been transformed nfTransf, # node has been transformed
nfSem # node has been checked for semantics nfSem # node has been checked for semantics

View file

@ -14,7 +14,7 @@ import
options, intsets, options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
rodutils, renderer, idgen, cgendata, ccgmerge rodutils, renderer, idgen, cgendata, ccgmerge, semfold
when options.hasTinyCBackend: when options.hasTinyCBackend:
import tccgen import tccgen

View file

@ -155,9 +155,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n) result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
of mLeU, mLeU64: of mLeU, mLeU64:
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n) result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
of mBitandI, mBitandI64, mAnd: result = newIntNodeT(getInt(a) and getInt(b), n) of mBitandI, mBitandI64, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
of mBitorI, mBitorI64, mOr: result = newIntNodeT(getInt(a) or getInt(b), n) of mBitorI, mBitorI64, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
of mBitxorI, mBitxorI64, mXor: result = newIntNodeT(getInt(a) xor getInt(b), n) of mBitxorI, mBitxorI64, mXor: result = newIntNodeT(a.getInt xor b.getInt, n)
of mAddU, mAddU64: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n) of mAddU, mAddU64: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
of mSubU, mSubU64: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n) of mSubU, mSubU64: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
of mMulU, mMulU64: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n) of mMulU, mMulU64: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
@ -199,7 +199,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
result = copyTree(a) result = copyTree(a)
result.typ = n.typ result.typ = n.typ
of mCompileOption: of mCompileOption:
result = newIntNodeT(Ord(commands.testCompileOption(getStr(a), n.info)), n) result = newIntNodeT(Ord(commands.testCompileOption(a.getStr, n.info)), n)
of mCompileOptionArg: of mCompileOptionArg:
result = newIntNodeT(Ord( result = newIntNodeT(Ord(
testCompileOptionArg(getStr(a), getStr(b), n.info)), n) testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
@ -315,6 +315,59 @@ proc foldConv*(n, a: PNode): PNode =
result = a result = a
result.typ = n.typ result.typ = n.typ
proc getArrayConstr(m: PSym, n: PNode): PNode =
if n.kind == nkBracket:
result = n
else:
result = getConstExpr(m, n)
if result == nil: result = n
proc foldArrayAccess(m: PSym, n: PNode): PNode =
var x = getConstExpr(m, n.sons[0])
if x == nil: return
var y = getConstExpr(m, n.sons[1])
if y == nil: return
var idx = getOrdValue(y)
case x.kind
of nkPar:
if (idx >= 0) and (idx < sonsLen(x)):
result = x.sons[int(idx)]
if result.kind == nkExprColonExpr: result = result.sons[1]
else:
LocalError(n.info, errIndexOutOfBounds)
of nkBracket, nkMetaNode:
if (idx >= 0) and (idx < sonsLen(x)): result = x.sons[int(idx)]
else: LocalError(n.info, errIndexOutOfBounds)
of nkStrLit..nkTripleStrLit:
result = newNodeIT(nkCharLit, x.info, n.typ)
if (idx >= 0) and (idx < len(x.strVal)):
result.intVal = ord(x.strVal[int(idx)])
elif idx == len(x.strVal):
nil
else:
LocalError(n.info, errIndexOutOfBounds)
else: nil
proc foldFieldAccess(m: PSym, n: PNode): PNode =
# a real field access; proc calls have already been transformed
var x = getConstExpr(m, n.sons[0])
if x == nil or x.kind != nkPar: return
var field = n.sons[1].sym
for i in countup(0, sonsLen(x) - 1):
var it = x.sons[i]
if it.kind != nkExprColonExpr:
# lookup per index:
result = x.sons[field.position]
if result.kind == nkExprColonExpr: result = result.sons[1]
return
if it.sons[0].sym.name.id == field.name.id:
result = x.sons[i].sons[1]
return
localError(n.info, errFieldXNotFound, field.name.s)
proc getConstExpr(m: PSym, n: PNode): PNode = proc getConstExpr(m: PSym, n: PNode): PNode =
result = nil result = nil
case n.kind case n.kind
@ -333,7 +386,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mNimrodPatch: result = newIntNodeT(VersionPatch, n) of mNimrodPatch: result = newIntNodeT(VersionPatch, n)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n) of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n) of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
of mHostCPU: result = newStrNodeT(toLower(platform.CPU[targetCPU].name), n) of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)
of mAppType: result = getAppType(n) of mAppType: result = getAppType(n)
of mNaN: result = newFloatNodeT(NaN, n) of mNaN: result = newFloatNodeT(NaN, n)
of mInf: result = newFloatNodeT(Inf, n) of mInf: result = newFloatNodeT(Inf, n)
@ -346,7 +399,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = copyNode(n) result = copyNode(n)
of nkIfExpr: of nkIfExpr:
result = getConstIfExpr(m, n) result = getConstIfExpr(m, n)
of nkCall, nkCommand, nkCallStrLit: of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix:
if n.sons[0].kind != nkSym: return if n.sons[0].kind != nkSym: return
var s = n.sons[0].sym var s = n.sons[0].sym
if s.kind != skProc: return if s.kind != skProc: return
@ -372,13 +425,13 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
{tyOpenArray, tySequence, tyString}: {tyOpenArray, tySequence, tyString}:
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
else: else:
var a = n.sons[1] var a = getArrayConstr(m, n.sons[1])
if a.kind == nkBracket: if a.kind == nkBracket:
# we can optimize it away: # we can optimize it away:
result = newIntNodeT(sonsLen(a)-1, n) result = newIntNodeT(sonsLen(a)-1, n)
of mLengthOpenArray: of mLengthOpenArray:
var a = n.sons[1] var a = getArrayConstr(m, n.sons[1])
if a.kind == nkBracket: if a.kind == nkBracket:
# we can optimize it away! This fixes the bug ``len(134)``. # we can optimize it away! This fixes the bug ``len(134)``.
result = newIntNodeT(sonsLen(a), n) result = newIntNodeT(sonsLen(a), n)
else: else:
@ -449,5 +502,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
var a = getConstExpr(m, n.sons[1]) var a = getConstExpr(m, n.sons[1])
if a == nil: return if a == nil: return
result = foldConv(n, a) result = foldConv(n, a)
else: of nkBracketExpr: result = foldArrayAccess(m, n)
of nkDotExpr: result = foldFieldAccess(m, n)
else:
nil nil

View file

@ -719,7 +719,9 @@ proc transform(c: PTransf, n: PNode): PTransNode =
else: else:
result = transformSons(c, n) result = transformSons(c, n)
var cnst = getConstExpr(c.module, PNode(result)) var cnst = getConstExpr(c.module, PNode(result))
if cnst != nil and (cnst.kind != nkBracket or cnst.len == 0): # we inline constants if they are not complex constants:
if cnst != nil and (cnst.kind notin {nkCurly, nkPar, nkBracket} or
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

@ -1,10 +1,8 @@
Version 0.8.14 Version 0.8.14
============== ==============
- optimize unused constants away (affected by HLO); get rid of nfAllConst - optimize unused constants away (affected by HLO)
- 'let x = y' - fix actors.nim; test with different thread var implementations
- fix actors.nim
- make threadvar efficient again on linux after testing
- dead code elim for JS backend - dead code elim for JS backend
@ -16,42 +14,14 @@ incremental compilation
- implement lib/pure/memfiles properly - implement lib/pure/memfiles properly
Destructors
-----------
A destructor is bound to a proc instead of a type. The proc is then called
an *init proc*. A destructor is called at
scope exit for the local variables (declared with ``var`` or ``let``)
that are initialized with its corresponding init proc:
.. code-block:: nimrod
proc autoOpen(filename: string): TFile {.destructor: close.} =
result = open(filename)
var f = autoOpen("abc.txt")
A template ``atScopeExit`` can easily be defined with this mechanism. However
unfortunately the regex problem is not solved at all:
.. code-block:: nimrod
if x =~ re"abc":
...
We really need some form of escape analysis; ``var`` or ``let`` is not enough!
Hm, but what if the procs declare that property:
.. code-block:: nimrod
proc `=~` (s: string, pattern: TRegex{.noEscape.}): bool
So it's bound to a type again?
version 0.9.0 version 0.9.0
============= =============
- test the sort implementation again - test the sort implementation again
- 'let x = y'
- const ptr/ref - const ptr/ref
- unsigned ints and bignums; requires abstract integer literal type - unsigned ints and bignums; requires abstract integer literal type:
use tyInt+node for that
- implement the high level optimizer - implement the high level optimizer
- warning for implicit openArray -> varargs convention - warning for implicit openArray -> varargs convention
- implement explicit varargs; **but** ``len(varargs)`` problem remains! - implement explicit varargs; **but** ``len(varargs)`` problem remains!
@ -64,7 +34,6 @@ version 0.9.0
- 'const' objects including case objects - 'const' objects including case objects
- os module should use Windows Unicode versions - os module should use Windows Unicode versions
- 64bit build for Windows - 64bit build for Windows
- codegen should use "NIM_CAST" macro and respect aliasing rules for GCC
- optional indentation for 'case' statement - optional indentation for 'case' statement
Bugs Bugs
@ -83,7 +52,7 @@ Bugs
- bug: DLL generation is broken; write at least a basic test - 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:relase`` 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!
@ -149,6 +118,7 @@ Low priority
is allocated is allocated
- timeout for locks - timeout for locks
- adapt thread var emulation to care about the new merge operation - adapt thread var emulation to care about the new merge operation
- codegen should use "NIM_CAST" macro and respect aliasing rules for GCC
Version 2 Version 2