constant folding for cnst[i] and cnst.attr
This commit is contained in:
parent
22115a2c6a
commit
299390a585
5 changed files with 78 additions and 49 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
44
todo.txt
44
todo.txt
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue