constant folding for cnst[i] and cnst.attr

This commit is contained in:
Araq
2011-10-29 23:54:50 +02:00
parent 22115a2c6a
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
nfBase8,
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
nfSem # node has been checked for semantics

View File

@@ -14,7 +14,7 @@ import
options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
rodutils, renderer, idgen, cgendata, ccgmerge
rodutils, renderer, idgen, cgendata, ccgmerge, semfold
when options.hasTinyCBackend:
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)
of mLeU, mLeU64:
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 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 mSubU, mSubU64: 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.typ = n.typ
of mCompileOption:
result = newIntNodeT(Ord(commands.testCompileOption(getStr(a), n.info)), n)
result = newIntNodeT(Ord(commands.testCompileOption(a.getStr, n.info)), n)
of mCompileOptionArg:
result = newIntNodeT(Ord(
testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
@@ -315,6 +315,59 @@ proc foldConv*(n, a: PNode): PNode =
result = a
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 =
result = nil
case n.kind
@@ -333,7 +386,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mNimrodPatch: result = newIntNodeT(VersionPatch, n)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), 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 mNaN: result = newFloatNodeT(NaN, n)
of mInf: result = newFloatNodeT(Inf, n)
@@ -346,7 +399,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = copyNode(n)
of nkIfExpr:
result = getConstIfExpr(m, n)
of nkCall, nkCommand, nkCallStrLit:
of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix:
if n.sons[0].kind != nkSym: return
var s = n.sons[0].sym
if s.kind != skProc: return
@@ -372,13 +425,13 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
{tyOpenArray, tySequence, tyString}:
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
else:
var a = n.sons[1]
var a = getArrayConstr(m, n.sons[1])
if a.kind == nkBracket:
# we can optimize it away:
result = newIntNodeT(sonsLen(a)-1, n)
of mLengthOpenArray:
var a = n.sons[1]
if a.kind == nkBracket:
var a = getArrayConstr(m, n.sons[1])
if a.kind == nkBracket:
# we can optimize it away! This fixes the bug ``len(134)``.
result = newIntNodeT(sonsLen(a), n)
else:
@@ -449,5 +502,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
var a = getConstExpr(m, n.sons[1])
if a == nil: return
result = foldConv(n, a)
else:
of nkBracketExpr: result = foldArrayAccess(m, n)
of nkDotExpr: result = foldFieldAccess(m, n)
else:
nil

View File

@@ -719,7 +719,9 @@ proc transform(c: PTransf, n: PNode): PTransNode =
else:
result = transformSons(c, n)
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
proc processTransf(context: PPassContext, n: PNode): PNode =

View File

@@ -1,10 +1,8 @@
Version 0.8.14
==============
- optimize unused constants away (affected by HLO); get rid of nfAllConst
- 'let x = y'
- fix actors.nim
- make threadvar efficient again on linux after testing
- optimize unused constants away (affected by HLO)
- fix actors.nim; test with different thread var implementations
- dead code elim for JS backend
@@ -16,42 +14,14 @@ incremental compilation
- 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
=============
- test the sort implementation again
- 'let x = y'
- 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
- warning for implicit openArray -> varargs convention
- implement explicit varargs; **but** ``len(varargs)`` problem remains!
@@ -64,7 +34,6 @@ version 0.9.0
- 'const' objects including case objects
- os module should use Windows Unicode versions
- 64bit build for Windows
- codegen should use "NIM_CAST" macro and respect aliasing rules for GCC
- optional indentation for 'case' statement
Bugs
@@ -83,7 +52,7 @@ Bugs
- bug: DLL generation is broken; write at least a basic test
- 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!
@@ -149,6 +118,7 @@ Low priority
is allocated
- timeout for locks
- 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