GC: get rid of pathological behaviour for stack marking
This commit is contained in:
parent
e390d8ec4a
commit
c40aac8e20
5 changed files with 326 additions and 323 deletions
|
|
@ -17,27 +17,27 @@
|
|||
# * introduces method dispatchers
|
||||
# * performs lambda lifting for closure support
|
||||
|
||||
import
|
||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
import
|
||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
|
||||
lambdalifting, sempass2, lowerings
|
||||
|
||||
# implementation
|
||||
|
||||
type
|
||||
type
|
||||
PTransNode* = distinct PNode
|
||||
|
||||
|
||||
PTransCon = ref TTransCon
|
||||
TTransCon{.final.} = object # part of TContext; stackable
|
||||
mapping: TIdNodeTable # mapping from symbols to nodes
|
||||
owner: PSym # current owner
|
||||
forStmt: PNode # current for stmt
|
||||
forLoopBody: PTransNode # transformed for loop body
|
||||
yieldStmts: int # we count the number of yield statements,
|
||||
forLoopBody: PTransNode # transformed for loop body
|
||||
yieldStmts: int # we count the number of yield statements,
|
||||
# because we need to introduce new variables
|
||||
# if we encounter the 2nd yield statement
|
||||
next: PTransCon # for stacking
|
||||
|
||||
|
||||
TTransfContext = object of passes.TPassContext
|
||||
module: PSym
|
||||
transCon: PTransCon # top of a TransCon stack
|
||||
|
|
@ -46,52 +46,52 @@ type
|
|||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||
PTransf = ref TTransfContext
|
||||
|
||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||
result = PTransNode(shallowCopy(a))
|
||||
|
||||
proc newTransNode(kind: TNodeKind, info: TLineInfo,
|
||||
sons: int): PTransNode {.inline.} =
|
||||
proc newTransNode(kind: TNodeKind, info: TLineInfo,
|
||||
sons: int): PTransNode {.inline.} =
|
||||
var x = newNodeI(kind, info)
|
||||
newSeq(x.sons, sons)
|
||||
result = x.PTransNode
|
||||
|
||||
proc newTransNode(kind: TNodeKind, n: PNode,
|
||||
sons: int): PTransNode {.inline.} =
|
||||
proc newTransNode(kind: TNodeKind, n: PNode,
|
||||
sons: int): PTransNode {.inline.} =
|
||||
var x = newNodeIT(kind, n.info, n.typ)
|
||||
newSeq(x.sons, sons)
|
||||
x.typ = n.typ
|
||||
result = x.PTransNode
|
||||
|
||||
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
||||
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
||||
var n = PNode(a)
|
||||
n.sons[i] = PNode(x)
|
||||
|
||||
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
||||
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
||||
var n = PNode(a)
|
||||
result = n.sons[i].PTransNode
|
||||
|
||||
|
||||
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
|
||||
proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
|
||||
|
||||
proc newTransCon(owner: PSym): PTransCon =
|
||||
proc newTransCon(owner: PSym): PTransCon =
|
||||
assert owner != nil
|
||||
new(result)
|
||||
initIdNodeTable(result.mapping)
|
||||
result.owner = owner
|
||||
|
||||
proc pushTransCon(c: PTransf, t: PTransCon) =
|
||||
proc pushTransCon(c: PTransf, t: PTransCon) =
|
||||
t.next = c.transCon
|
||||
c.transCon = t
|
||||
|
||||
proc popTransCon(c: PTransf) =
|
||||
proc popTransCon(c: PTransf) =
|
||||
if (c.transCon == nil): internalError("popTransCon")
|
||||
c.transCon = c.transCon.next
|
||||
|
||||
proc getCurrOwner(c: PTransf): PSym =
|
||||
proc getCurrOwner(c: PTransf): PSym =
|
||||
if c.transCon != nil: result = c.transCon.owner
|
||||
else: result = c.module
|
||||
|
||||
proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
|
||||
|
||||
proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
|
||||
result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
|
||||
result.typ = skipTypes(typ, {tyGenericInst})
|
||||
incl(result.flags, sfFromGeneric)
|
||||
|
|
@ -100,10 +100,10 @@ proc transform(c: PTransf, n: PNode): PTransNode
|
|||
|
||||
proc transformSons(c: PTransf, n: PNode): PTransNode =
|
||||
result = newTransNode(n)
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
result[i] = transform(c, n.sons[i])
|
||||
|
||||
proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
||||
proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
||||
result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
|
||||
result[0] = PTransNode(le)
|
||||
result[1] = ri
|
||||
|
|
@ -113,30 +113,30 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
|||
# return liftIterSym(n)
|
||||
var b: PNode
|
||||
var tc = c.transCon
|
||||
if sfBorrow in n.sym.flags:
|
||||
if sfBorrow in n.sym.flags:
|
||||
# simply exchange the symbol:
|
||||
b = n.sym.getBody
|
||||
if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
|
||||
b = newSymNode(b.sym)
|
||||
b.info = n.info
|
||||
else:
|
||||
else:
|
||||
b = n
|
||||
while tc != nil:
|
||||
while tc != nil:
|
||||
result = idNodeTableGet(tc.mapping, b.sym)
|
||||
if result != nil: return
|
||||
tc = tc.next
|
||||
result = b
|
||||
|
||||
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
||||
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
||||
result = PTransNode(transformSymAux(c, n))
|
||||
|
||||
proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
||||
result = newTransNode(v)
|
||||
for i in countup(0, sonsLen(v)-1):
|
||||
var it = v.sons[i]
|
||||
if it.kind == nkCommentStmt:
|
||||
if it.kind == nkCommentStmt:
|
||||
result[i] = PTransNode(it)
|
||||
elif it.kind == nkIdentDefs:
|
||||
elif it.kind == nkIdentDefs:
|
||||
if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection")
|
||||
internalAssert(it.len == 3)
|
||||
var newVar = copySym(it.sons[0].sym)
|
||||
|
|
@ -153,12 +153,12 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
|||
defs[1] = it.sons[1].PTransNode
|
||||
defs[2] = transform(c, it.sons[2])
|
||||
result[i] = defs
|
||||
else:
|
||||
if it.kind != nkVarTuple:
|
||||
else:
|
||||
if it.kind != nkVarTuple:
|
||||
internalError(it.info, "transformVarSection: not nkVarTuple")
|
||||
var L = sonsLen(it)
|
||||
var defs = newTransNode(it.kind, it.info, L)
|
||||
for j in countup(0, L-3):
|
||||
for j in countup(0, L-3):
|
||||
var newVar = copySym(it.sons[j].sym)
|
||||
incl(newVar.flags, sfFromGeneric)
|
||||
newVar.owner = getCurrOwner(c)
|
||||
|
|
@ -188,12 +188,12 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
|
|||
else:
|
||||
result[i] = PTransNode(it)
|
||||
|
||||
proc hasContinue(n: PNode): bool =
|
||||
proc hasContinue(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
|
||||
of nkContinueStmt: result = true
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if hasContinue(n.sons[i]): return true
|
||||
|
||||
proc newLabel(c: PTransf, n: PNode): PSym =
|
||||
|
|
@ -224,10 +224,10 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode =
|
|||
discard c.breakSyms.pop
|
||||
result[0] = newSymNode(labl).PTransNode
|
||||
|
||||
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||
# What if it contains "continue" and "break"? "break" needs
|
||||
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||
# What if it contains "continue" and "break"? "break" needs
|
||||
# an explicit label too, but not the same!
|
||||
|
||||
|
||||
# We fix this here by making every 'break' belong to its enclosing loop
|
||||
# and changing all breaks that belong to a 'block' by annotating it with
|
||||
# a label (if it hasn't one already).
|
||||
|
|
@ -239,7 +239,7 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
|||
result[0] = newSymNode(labl).PTransNode
|
||||
result[1] = transform(c, n)
|
||||
discard c.contSyms.pop()
|
||||
else:
|
||||
else:
|
||||
result = transform(c, n)
|
||||
|
||||
proc transformWhile(c: PTransf; n: PNode): PTransNode =
|
||||
|
|
@ -273,27 +273,27 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode =
|
|||
result = transformSons(c, n)
|
||||
result[0] = newSymNode(labl).PTransNode
|
||||
|
||||
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
||||
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
||||
# XXX: BUG: what if `n` is an expression with side-effects?
|
||||
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
||||
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
||||
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||
transform(c, newTupleAccess(n, i))))
|
||||
|
||||
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
result = transformSym(c, n)
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
# nothing to be done for leaves:
|
||||
result = PTransNode(n)
|
||||
of nkVarSection, nkLetSection:
|
||||
result = transformVarSection(c, n)
|
||||
else:
|
||||
result = newTransNode(n)
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
result[i] = introduceNewLocalVars(c, n.sons[i])
|
||||
|
||||
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||
result = newTransNode(nkStmtList, n.info, 0)
|
||||
var e = n.sons[0]
|
||||
# c.transCon.forStmt.len == 3 means that there is one for loop variable
|
||||
|
|
@ -301,21 +301,21 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
|
|||
if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple and
|
||||
c.transCon.forStmt.len != 3:
|
||||
e = skipConv(e)
|
||||
if e.kind == nkPar:
|
||||
for i in countup(0, sonsLen(e) - 1):
|
||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||
if e.kind == nkPar:
|
||||
for i in countup(0, sonsLen(e) - 1):
|
||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||
transform(c, e.sons[i])))
|
||||
else:
|
||||
else:
|
||||
unpackTuple(c, e, result)
|
||||
else:
|
||||
else:
|
||||
var x = transform(c, e)
|
||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
|
||||
|
||||
|
||||
inc(c.transCon.yieldStmts)
|
||||
if c.transCon.yieldStmts <= 1:
|
||||
# common case
|
||||
add(result, c.transCon.forLoopBody)
|
||||
else:
|
||||
else:
|
||||
# we need to introduce new local variables:
|
||||
add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
|
||||
|
||||
|
|
@ -340,25 +340,25 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
|||
if n.sons[0].kind == a or n.sons[0].kind == b:
|
||||
# addr ( deref ( x )) --> x
|
||||
result = PTransNode(n.sons[0].sons[0])
|
||||
|
||||
proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||
|
||||
proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||
# numeric types need range checks:
|
||||
var dest = skipTypes(n.typ, abstractVarRange)
|
||||
var source = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||
case dest.kind
|
||||
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
|
||||
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
|
||||
# we don't include uint and uint64 here as these are no ordinal types ;-)
|
||||
if not isOrdinalType(source):
|
||||
# float -> int conversions. ugh.
|
||||
result = transformSons(c, n)
|
||||
elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
|
||||
lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
|
||||
lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
|
||||
# BUGFIX: simply leave n as it is; we need a nkConv node,
|
||||
# but no range check:
|
||||
result = transformSons(c, n)
|
||||
else:
|
||||
else:
|
||||
# generate a range check:
|
||||
if dest.kind == tyInt64 or source.kind == tyInt64:
|
||||
if dest.kind == tyInt64 or source.kind == tyInt64:
|
||||
result = newTransNode(nkChckRange64, n, 3)
|
||||
else:
|
||||
result = newTransNode(nkChckRange, n, 3)
|
||||
|
|
@ -368,7 +368,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
|||
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
|
||||
of tyFloat..tyFloat128:
|
||||
# XXX int64 -> float conversion?
|
||||
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
||||
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
||||
result = newTransNode(nkChckRangeF, n, 3)
|
||||
dest = skipTypes(n.typ, abstractVar)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
|
|
@ -378,81 +378,81 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
|||
result = transformSons(c, n)
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = transform(c, n.sons[1])
|
||||
of tyCString:
|
||||
if source.kind == tyString:
|
||||
of tyCString:
|
||||
if source.kind == tyString:
|
||||
result = newTransNode(nkStringToCString, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of tyString:
|
||||
if source.kind == tyCString:
|
||||
of tyString:
|
||||
if source.kind == tyCString:
|
||||
result = newTransNode(nkCStringToString, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of tyRef, tyPtr:
|
||||
of tyRef, tyPtr:
|
||||
dest = skipTypes(dest, abstractPtrs)
|
||||
source = skipTypes(source, abstractPtrs)
|
||||
if source.kind == tyObject:
|
||||
if source.kind == tyObject:
|
||||
var diff = inheritanceDiff(dest, source)
|
||||
if diff < 0:
|
||||
if diff < 0:
|
||||
result = newTransNode(nkObjUpConv, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
elif diff > 0:
|
||||
elif diff > 0:
|
||||
result = newTransNode(nkObjDownConv, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
else:
|
||||
else:
|
||||
result = transform(c, n.sons[1])
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of tyObject:
|
||||
of tyObject:
|
||||
var diff = inheritanceDiff(dest, source)
|
||||
if diff < 0:
|
||||
if diff < 0:
|
||||
result = newTransNode(nkObjUpConv, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
elif diff > 0:
|
||||
elif diff > 0:
|
||||
result = newTransNode(nkObjDownConv, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
else:
|
||||
else:
|
||||
result = transform(c, n.sons[1])
|
||||
of tyGenericParam, tyOrdinal:
|
||||
result = transform(c, n.sons[1])
|
||||
# happens sometimes for generated assignments, etc.
|
||||
else:
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
|
||||
type
|
||||
TPutArgInto = enum
|
||||
|
||||
type
|
||||
TPutArgInto = enum
|
||||
paDirectMapping, paFastAsgn, paVarAsgn
|
||||
|
||||
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||
# This analyses how to treat the mapping "formal <-> arg" in an
|
||||
# inline context.
|
||||
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
return paDirectMapping # XXX really correct?
|
||||
# what if ``arg`` has side-effects?
|
||||
case arg.kind
|
||||
of nkEmpty..nkNilLit:
|
||||
of nkEmpty..nkNilLit:
|
||||
result = paDirectMapping
|
||||
of nkPar, nkCurly, nkBracket:
|
||||
of nkPar, nkCurly, nkBracket:
|
||||
result = paFastAsgn
|
||||
for i in countup(0, sonsLen(arg) - 1):
|
||||
if putArgInto(arg.sons[i], formal) != paDirectMapping: return
|
||||
for i in countup(0, sonsLen(arg) - 1):
|
||||
if putArgInto(arg.sons[i], formal) != paDirectMapping: return
|
||||
result = paDirectMapping
|
||||
else:
|
||||
else:
|
||||
if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
|
||||
else: result = paFastAsgn
|
||||
|
||||
|
||||
proc findWrongOwners(c: PTransf, n: PNode) =
|
||||
if n.kind == nkVarSection:
|
||||
let x = n.sons[0].sons[0]
|
||||
if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
|
||||
internalError(x.info, "bah " & x.sym.name.s & " " &
|
||||
internalError(x.info, "bah " & x.sym.name.s & " " &
|
||||
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
|
||||
else:
|
||||
for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
|
||||
|
||||
proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
# generate access statements for the parameters (unless they are constant)
|
||||
# put mapping from formal parameters to actual parameters
|
||||
if n.kind != nkForStmt: internalError(n.info, "transformFor")
|
||||
|
|
@ -466,26 +466,26 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
|||
result[0] = newSymNode(labl).PTransNode
|
||||
|
||||
if call.typ.kind != tyIter and
|
||||
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
||||
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
||||
call.sons[0].sym.kind != skIterator):
|
||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
||||
result[1] = lambdalifting.liftForLoop(n).PTransNode
|
||||
discard c.breakSyms.pop
|
||||
return result
|
||||
|
||||
|
||||
#echo "transforming: ", renderTree(n)
|
||||
var stmtList = newTransNode(nkStmtList, n.info, 0)
|
||||
|
||||
|
||||
var loopBody = transformLoopBody(c, n.sons[length-1])
|
||||
|
||||
result[1] = stmtList
|
||||
discard c.breakSyms.pop
|
||||
|
||||
var v = newNodeI(nkVarSection, n.info)
|
||||
for i in countup(0, length - 3):
|
||||
for i in countup(0, length - 3):
|
||||
addVar(v, copyTree(n.sons[i])) # declare new vars
|
||||
add(stmtList, v.PTransNode)
|
||||
|
||||
|
||||
# Bugfix: inlined locals belong to the invoking routine, not to the invoked
|
||||
# iterator!
|
||||
let iter = call.sons[0].sym
|
||||
|
|
@ -496,9 +496,9 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
|||
if iter.kind != skIterator: return result
|
||||
# generate access statements for the parameters (unless they are constant)
|
||||
pushTransCon(c, newC)
|
||||
for i in countup(1, sonsLen(call) - 1):
|
||||
for i in countup(1, sonsLen(call) - 1):
|
||||
var arg = transform(c, call.sons[i]).PNode
|
||||
var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
|
||||
var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
|
||||
if arg.typ.kind == tyIter: continue
|
||||
case putArgInto(arg, formal.typ)
|
||||
of paDirectMapping:
|
||||
|
|
@ -527,20 +527,20 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
|||
popInfoContext()
|
||||
popTransCon(c)
|
||||
# echo "transformed: ", stmtList.PNode.renderTree
|
||||
|
||||
proc getMagicOp(call: PNode): TMagic =
|
||||
|
||||
proc getMagicOp(call: PNode): TMagic =
|
||||
if call.sons[0].kind == nkSym and
|
||||
call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
|
||||
call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
|
||||
result = call.sons[0].sym.magic
|
||||
else:
|
||||
result = mNone
|
||||
|
||||
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||
# removes `elif` branches of a case stmt
|
||||
# adds ``else: nil`` if needed for the code generator
|
||||
result = newTransNode(nkCaseStmt, n, 0)
|
||||
var ifs = PTransNode(nil)
|
||||
for i in 0 .. sonsLen(n)-1:
|
||||
for i in 0 .. sonsLen(n)-1:
|
||||
var it = n.sons[i]
|
||||
var e = transform(c, it)
|
||||
case it.kind
|
||||
|
|
@ -564,8 +564,8 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
|
|||
var elseBranch = newTransNode(nkElse, n.info, 1)
|
||||
elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
|
||||
add(result, elseBranch)
|
||||
|
||||
proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
||||
|
||||
proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
||||
# XXX this is really bad; transf should use a proper AST visitor
|
||||
if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
|
||||
result = n.PTransNode
|
||||
|
|
@ -573,45 +573,45 @@ proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
|||
result = newTransNode(n)
|
||||
for i in 0 .. < n.len:
|
||||
result[i] = transform(c, skipConv(n.sons[i]))
|
||||
|
||||
proc getMergeOp(n: PNode): PSym =
|
||||
|
||||
proc getMergeOp(n: PNode): PSym =
|
||||
case n.kind
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCallStrLit:
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCallStrLit:
|
||||
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skProc) and
|
||||
(sfMerge in n.sons[0].sym.flags):
|
||||
(sfMerge in n.sons[0].sym.flags):
|
||||
result = n.sons[0].sym
|
||||
else: discard
|
||||
|
||||
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
||||
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
||||
let op2 = getMergeOp(a)
|
||||
if op2 != nil and
|
||||
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
|
||||
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
|
||||
for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
|
||||
else:
|
||||
else:
|
||||
addSon(d, copyTree(a))
|
||||
|
||||
proc flattenTree(root: PNode): PNode =
|
||||
|
||||
proc flattenTree(root: PNode): PNode =
|
||||
let op = getMergeOp(root)
|
||||
if op != nil:
|
||||
if op != nil:
|
||||
result = copyNode(root)
|
||||
addSon(result, copyTree(root.sons[0]))
|
||||
flattenTreeAux(result, root, op)
|
||||
else:
|
||||
else:
|
||||
result = root
|
||||
|
||||
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||
var n = flattenTree(n)
|
||||
let op = getMergeOp(n)
|
||||
let magic = getMagic(n)
|
||||
if op != nil and op.magic != mNone and n.len >= 3:
|
||||
if op != nil and op.magic != mNone and n.len >= 3:
|
||||
result = newTransNode(nkCall, n, 0)
|
||||
add(result, transform(c, n.sons[0]))
|
||||
var j = 1
|
||||
while j < sonsLen(n):
|
||||
while j < sonsLen(n):
|
||||
var a = transform(c, n.sons[j]).PNode
|
||||
inc(j)
|
||||
if isConstExpr(a):
|
||||
if isConstExpr(a):
|
||||
while (j < sonsLen(n)):
|
||||
let b = transform(c, n.sons[j]).PNode
|
||||
if not isConstExpr(b): break
|
||||
|
|
@ -640,7 +640,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
|||
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
|
||||
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
|
||||
cnst.len != 0
|
||||
|
||||
proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||
|
|
@ -673,11 +673,11 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
|||
else:
|
||||
result = n
|
||||
|
||||
proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
result = transformSym(c, n)
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
# nothing to be done for leaves:
|
||||
result = PTransNode(n)
|
||||
of nkBracketExpr: result = transformArrayAccess(c, n)
|
||||
|
|
@ -702,7 +702,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
||||
if n.kind == nkMethodDef: methodDef(s, false)
|
||||
result = PTransNode(n)
|
||||
of nkForStmt:
|
||||
of nkForStmt:
|
||||
result = transformFor(c, n)
|
||||
of nkParForStmt:
|
||||
result = transformSons(c, n)
|
||||
|
|
@ -713,14 +713,14 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
add(result, PTransNode(newSymNode(labl)))
|
||||
of nkBreakStmt: result = transformBreak(c, n)
|
||||
of nkWhileStmt: result = transformWhile(c, n)
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCallStrLit:
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCallStrLit:
|
||||
result = transformCall(c, n)
|
||||
of nkAddr, nkHiddenAddr:
|
||||
of nkAddr, nkHiddenAddr:
|
||||
result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
result = transformConv(c, n)
|
||||
of nkDiscardStmt:
|
||||
result = PTransNode(n)
|
||||
|
|
@ -730,7 +730,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
# ensure that e.g. discard "some comment" gets optimized away
|
||||
# completely:
|
||||
result = PTransNode(newNode(nkCommentStmt))
|
||||
of nkCommentStmt, nkTemplateDef:
|
||||
of nkCommentStmt, nkTemplateDef:
|
||||
return n.PTransNode
|
||||
of nkConstSection:
|
||||
# do not replace ``const c = 3`` with ``const 3 = 3``
|
||||
|
|
@ -744,10 +744,10 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
result = transformVarSection(c, n)
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of nkYieldStmt:
|
||||
of nkYieldStmt:
|
||||
if c.inlining > 0:
|
||||
result = transformYield(c, n)
|
||||
else:
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of nkBlockStmt, nkBlockExpr:
|
||||
result = transformBlock(c, n)
|
||||
|
|
@ -764,7 +764,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||
result = PTransNode(cnst) # do not miss an optimization
|
||||
|
||||
proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
||||
proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
||||
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
||||
# this step! We have to rely that the semantic pass transforms too errornous
|
||||
# nodes into an empty node.
|
||||
|
|
@ -774,7 +774,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
|||
popTransCon(c)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc openTransf(module: PSym, filename: string): PTransf =
|
||||
proc openTransf(module: PSym, filename: string): PTransf =
|
||||
new(result)
|
||||
result.contSyms = @[]
|
||||
result.breakSyms = @[]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue