Change the order of compilation passes, transformation is made lazy at code gen (#8489)

* Ast no transformation
* Add getImplNoTransform to the macros module
* progress on delaying transf
* Fix methods tranformation
* Fix lazy lambdalifting
* fix create thread wrapper
* transform for lambda lifting
* improve getImplTransformed
* Fix destructor tests
* try to fix nimprof for linux
This commit is contained in:
cooldome
2018-10-18 19:21:25 +01:00
committed by Andreas Rumpf
parent 15dbd973de
commit eaca5be9d6
22 changed files with 188 additions and 85 deletions

View File

@@ -660,7 +660,7 @@ type
mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo,
mNimvm, mIntDefine, mStrDefine, mRunnableExamples,
mException, mBuiltinType, mSymOwner, mUncheckedArray
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf
# things that we can evaluate safely at compile time, even if not asked for it:
const
@@ -811,7 +811,7 @@ type
of routineKinds:
procInstCache*: seq[PInstantiation]
gcUnsafetyReason*: PSym # for better error messages wrt gcsafe
#scope*: PScope # the scope where the proc was defined
transformedBody*: PNode # cached body after transf pass
of skModule, skPackage:
# modules keep track of the generic symbols they use from other modules.
# this is because in incremental compilation, when a module is about to

View File

@@ -14,7 +14,7 @@ import
nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils
lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils, transf
import strutils except `%` # collides with ropes.`%`
@@ -845,6 +845,8 @@ proc genProcAux(m: BModule, prc: PSym) =
var header = genProcHeader(m, prc)
var returnStmt: Rope = nil
assert(prc.ast != nil)
let procBody = transformBody(m.g.graph, prc, cache = false)
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
if resultPos >= prc.ast.len:
internalError(m.config, prc.info, "proc has no result symbol")
@@ -852,7 +854,7 @@ proc genProcAux(m: BModule, prc: PSym) =
let res = resNode.sym # get result symbol
if not isInvalidReturnType(m.config, prc.typ.sons[0]):
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(prc.getBody); val != nil):
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
var decl = localVarDecl(p, resNode)
var a: TLoc
initLocExprSingleUse(p, val, a)
@@ -873,7 +875,7 @@ proc genProcAux(m: BModule, prc: PSym) =
# global is either 'nil' or points to valid memory and so the RC operation
# succeeds without touching not-initialized memory.
if sfNoInit in prc.flags: discard
elif allPathsAsgnResult(prc.getBody) == InitSkippable: discard
elif allPathsAsgnResult(procBody) == InitSkippable: discard
else:
resetLoc(p, res.loc)
if skipTypes(res.typ, abstractInst).kind == tyArray:
@@ -885,7 +887,7 @@ proc genProcAux(m: BModule, prc: PSym) =
if param.typ.isCompileTimeOnly: continue
assignParam(p, param)
closureSetup(p, prc)
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
genStmts(p, procBody) # modifies p.locals, p.init, etc.
var generatedProc: Rope
if sfNoReturn in prc.flags:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
@@ -1522,7 +1524,8 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
m.initProc.options = initProcOptions(m)
#softRnl = if optLineDir in m.config.options: noRnl else: rnl
# XXX replicate this logic!
genStmts(m.initProc, n)
let tranformed_n = transformStmt(m.g.graph, m.module, n)
genStmts(m.initProc, tranformed_n)
proc finishModule(m: BModule) =
var i = 0

View File

@@ -281,6 +281,7 @@ proc genDispatcher(g: ModuleGraph; methods: TSymSeq, relevantCols: IntSet): PSym
else:
disp = ret
nilchecks.add disp
nilchecks.flags.incl nfTransf # should not be further transformed
result.ast.sons[bodyPos] = nilchecks
proc generateMethodDispatchers*(g: ModuleGraph): PNode =

View File

@@ -70,7 +70,7 @@ proc isLetLocation(m: PNode, isApprox: bool): bool =
n = n.sons[0]
inc derefs
of nkBracketExpr:
if isConstExpr(n.sons[1]) or isLet(n.sons[1]):
if isConstExpr(n.sons[1]) or isLet(n.sons[1]) or isConstExpr(n.sons[1].skipConv):
n = n.sons[0]
else: return
of nkHiddenStdConv, nkHiddenSubConv, nkConv:

View File

@@ -32,7 +32,7 @@ import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
times, ropes, math, passes, ccgutils, wordrecg, renderer,
intsets, cgmeth, lowerings, sighashes, lineinfos, rodutils, pathutils
intsets, cgmeth, lowerings, sighashes, lineinfos, rodutils, pathutils, transf
from modulegraphs import ModuleGraph, PPassContext
@@ -2021,7 +2021,8 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
else:
returnStmt = "return $#;$n" % [a.res]
p.nested: genStmt(p, prc.getBody)
let transformed_body = transformBody(oldProc.module.graph, prc, cache = false)
p.nested: genStmt(p, transformed_body)
var def: Rope
if not prc.constraint.isNil:
@@ -2271,7 +2272,8 @@ proc genModule(p: PProc, n: PNode) =
add(p.body, frameCreate(p,
makeJSString("module " & p.module.module.name.s),
makeJSString(toFilename(p.config, p.module.module.info))))
genStmt(p, n)
let n_transformed = transformStmt(p.module.graph, p.module.module, n)
genStmt(p, n_transformed)
if optStackTrace in p.options:
add(p.body, frameDestroy(p))

View File

@@ -11,7 +11,8 @@
import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos,
transf
discard """
The basic approach is that captured vars need to be put on the heap and
@@ -257,7 +258,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
# add 'new' statement:
result.add newCall(getSysSym(g, n.info, "internalNew"), env)
result.add makeClosure(g, iter, env, n.info)
proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
let envParam = getHiddenParam(g, owner)
let obj = envParam.typ.lastSon
@@ -390,7 +391,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
if innerProc:
if s.isIterator: c.somethingToDo = true
if not c.processed.containsOrIncl(s.id):
detectCapturedVars(s.getBody, s, c)
let body = transformBody(c.graph, s)
detectCapturedVars(body, s, c)
let ow = s.skipGenericOwner
if ow == owner:
if owner.isIterator:
@@ -651,14 +653,17 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
# echo renderTree(s.getBody, {renderIds})
let oldInContainer = c.inContainer
c.inContainer = 0
var body = liftCapturedVars(s.getBody, s, d, c)
var body = transformBody(d.graph, s)
body = liftCapturedVars(body, s, d, c)
if c.envvars.getOrDefault(s.id).isNil:
s.ast.sons[bodyPos] = body
s.transformedBody = body
else:
s.ast.sons[bodyPos] = newTree(nkStmtList, rawClosureCreation(s, d, c), body)
s.transformedBody = newTree(nkStmtList, rawClosureCreation(s, d, c), body)
c.inContainer = oldInContainer
if s.typ.callConv == ccClosure:
result = symToClosure(n, owner, d, c)
elif s.id in d.capturedVars:
if s.owner != owner:
result = accessViaEnvParam(d.graph, n, owner)

View File

@@ -405,6 +405,8 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
varSection, varInit, call, barrier, fv: PNode;
spawnKind: TSpawnResult): PSym =
var body = newNodeI(nkStmtList, f.info)
body.flags.incl nfTransf # do not transform further
var threadLocalBarrier: PSym
if barrier != nil:
var varSection2 = newNodeI(nkVarSection, barrier.info)

View File

@@ -583,7 +583,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
result = buildEchoStmt(c, result)
if c.config.cmd == cmdIdeTools:
appendToModule(c.module, result)
result = transformStmt(c.graph, c.module, result)
trackTopLevelStmt(c.graph, c.module, result)
proc recoverContext(c: PContext) =
# clean up in case of a semantic error: We clean up the stacks, etc. This is

View File

@@ -413,14 +413,15 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
result = newStrNodeT("console", n, g)
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
var err = false
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
else:
err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
if err:
localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ))
if tfUncheckedArray notin n.typ.flags:
var err = false
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
else:
err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
if err:
localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ))
proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
let dstTyp = skipTypes(n.typ, abstractRange)

View File

@@ -146,9 +146,8 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
freshGenSyms(b, result, orig, symMap)
b = semProcBody(c, b)
b = hloBody(c, b)
n.sons[bodyPos] = transformBody(c.graph, c.module, b, result)
#echo "code instantiated ", result.name.s
result.ast[bodyPos] = hloBody(c, b)
trackProc(c.graph, result, result.ast[bodyPos])
excl(result.flags, sfForward)
dec c.inGenericInst

View File

@@ -9,7 +9,7 @@
import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, strutils, options, guards, writetracking, lineinfos,
wordrecg, strutils, options, guards, writetracking, lineinfos, semfold,
modulegraphs
when defined(useDfa):
@@ -48,6 +48,7 @@ type
tags: PNode # list of tags
bottom, inTryStmt: int
owner: PSym
owner_module: PSym
init: seq[int] # list of initialized variables
guards: TModel # nested guards
locked: seq[PNode] # locked locations
@@ -562,8 +563,10 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
var effectList = op.n.sons[0]
let s = n.skipConv
if s.kind == nkSym and s.sym.kind in routineKinds:
var s = n.skipConv
if s.kind == nkCast and s[1].typ.kind == tyProc:
s = s[1]
if s.kind == nkSym and s.sym.kind in routineKinds and isNoEffectList(effectList):
propagateEffects(tracked, n, s.sym)
elif isNoEffectList(effectList):
if isForwardedProc(n):
@@ -709,9 +712,13 @@ proc track(tracked: PEffects, n: PNode) =
for i in 0 ..< safeLen(n):
track(tracked, n.sons[i])
of nkCallKinds:
if getConstExpr(tracked.owner_module, n, tracked.graph) != nil:
return
# p's effects are ours too:
let a = n.sons[0]
var a = n.sons[0]
let op = a.typ
if a.kind == nkCast and a[1].typ.kind == tyProc:
a = a[1]
# XXX: in rare situations, templates and macros will reach here after
# calling getAst(templateOrMacro()). Currently, templates and macros
# are indistinguishable from normal procs (both have tyProc type) and
@@ -934,6 +941,7 @@ proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects) =
t.exc = effects.sons[exceptionEffects]
t.tags = effects.sons[tagEffects]
t.owner = s
t.owner_module = s.getModule
t.init = @[]
t.guards.s = @[]
t.guards.o = initOperators(g)

View File

@@ -1328,8 +1328,8 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc)
addResultNode(c, n)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
trackProc(c.graph, s, s.ast[bodyPos])
popProcCon(c)
elif efOperand notin flags:
localError(c.config, n.info, errGenericLambdaNotAllowed)
@@ -1369,8 +1369,8 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
pushProcCon(c, s)
addResult(c, n.typ.sons[0], n.info, skProc)
addResultNode(c, n)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
trackProc(c.graph, s, s.ast[bodyPos])
popProcCon(c)
popOwner(c)
closeScope(c)
@@ -1683,10 +1683,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if lfDynamicLib notin s.loc.flags:
# no semantic checking for importc:
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
s.ast[bodyPos] = hloBody(c, semProcBody(c, n.sons[bodyPos]))
# unfortunately we cannot skip this step when in 'system.compiles'
# context as it may even be evaluated in 'system.compiles':
n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s)
trackProc(c.graph, s, s.ast[bodyPos])
else:
if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info))

View File

@@ -30,6 +30,11 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
localError(conf, info, "type 'var var' is not allowed")
elif computeSize(conf, t) == szIllegalRecursion:
localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'")
t = typ.skipTypes({tyGenericInst})
if t.kind == tyArray and tfUncheckedArray in t.flags:
t[0].flags.incl tfUncheckedArray # mark range of unchecked array also unchecked
when false:
if t.kind == tyObject and t.sons[0] != nil:
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:

View File

@@ -21,9 +21,13 @@
import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups,
idents, renderer, types, passes, semfold, magicsys, cgmeth,
lambdalifting, sempass2, lowerings, destroyer, liftlocals, closureiters,
sempass2, lowerings, destroyer, liftlocals,
modulegraphs, lineinfos
proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode
import closureiters, lambdalifting
type
PTransNode* = distinct PNode
@@ -62,18 +66,25 @@ proc newTransNode(kind: TNodeKind, n: PNode,
var x = newNodeIT(kind, n.info, n.typ)
newSeq(x.sons, sons)
x.typ = n.typ
# x.flags = n.flags
result = x.PTransNode
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
proc len(a: PTransNode): int {.inline.} = sonsLen(a.PNode)
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
var n = PNode(a)
n.sons[i] = PNode(x)
proc `[]=`(a: PTransNode, i: BackwardsIndex, x: PTransNode) {.inline.} =
`[]=`(a, a.len - i.int, x)
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 `[]`(a: PTransNode, i: BackwardsIndex): PTransNode {.inline.} =
`[]`(a, a.len - i.int)
proc newTransCon(owner: PSym): PTransCon =
assert owner != nil
@@ -118,6 +129,8 @@ proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PTransNode): PTrans
proc transformSymAux(c: PTransf, n: PNode): PNode =
let s = n.sym
if s.typ != nil and s.typ.callConv == ccClosure:
if s.kind in routineKinds:
discard transformBody(c.graph, s)
if s.kind == skIterator:
if c.tooEarly: return n
else: return liftIterSym(c.graph, n, getCurrOwner(c))
@@ -146,7 +159,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
return
tc = tc.next
result = b
proc transformSym(c: PTransf, n: PNode): PTransNode =
result = PTransNode(transformSymAux(c, n))
@@ -561,9 +574,10 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
c.breakSyms.add(labl)
if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
call.sons[0].typ.callConv == ccClosure:
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
n.sons[length-2] = transform(c, n.sons[length-2]).PNode
result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
result[1] = n.PTransNode
result[1][^1] = transformLoopBody(c, n[^1])
result[1][^2] = transform(c, n[^2])
result[1] = lambdalifting.liftForLoop(c.graph, result[1].PNode, getCurrOwner(c)).PTransNode
discard c.breakSyms.pop
return result
@@ -617,7 +631,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
idNodeTablePut(newC.mapping, formal, temp)
var body = iter.getBody.copyTree
let body = transformBody(c.graph, iter).copyTree
pushInfoContext(c.graph.config, n.info)
# XXX optimize this somehow. But the check "c.inlining" is not correct:
var symMap: TIdTable
@@ -1040,27 +1054,36 @@ template liftDefer(c, root) =
if c.deferDetected:
liftDeferAux(root)
proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
if nfTransf in n.flags or prc.kind in {skTemplate}:
result = n
proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
assert prc.kind in routineKinds
if prc.transformedBody != nil:
result = prc.transformedBody
elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}:
result = prc.ast[bodyPos]
else:
var c = openTransf(g, module, "")
result = liftLambdas(g, prc, n, c.tooEarly)
#result = n
prc.transformedBody = newNode(nkEmpty) # protects from recursion
var c = openTransf(g, prc.getModule, "")
result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
result = processTransf(c, result, prc)
liftDefer(c, result)
#result = liftLambdas(prc, result)
when useEffectSystem: trackProc(g, prc, result)
result = liftLocalsIfRequested(prc, result, g.cache, g.config)
if c.needsDestroyPass: #and newDestructors:
result = injectDestructorCalls(g, prc, result)
if prc.isIterator:
result = g.transformClosureIterator(prc, result)
incl(result.flags, nfTransf)
#if prc.name.s == "testbody":
# echo renderTree(result)
let cache = cache or prc.typ.callConv == ccInline
if cache:
# genProc for inline procs will be called multiple times from diffrent modules,
# it is important to transform exactly once to get sym ids and locations right
prc.transformedBody = result
else:
prc.transformedBody = nil
proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
if nfTransf in n.flags:
@@ -1070,9 +1093,6 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
result = processTransf(c, n, module)
liftDefer(c, result)
#result = liftLambdasForTopLevel(module, result)
when useEffectSystem: trackTopLevelStmt(g, module, result)
#if n.info ?? "temp.nim":
# echo renderTree(result, {renderIds})
if c.needsDestroyPass:
result = injectDestructorCalls(g, module, result)
incl(result.flags, nfTransf)

View File

@@ -924,6 +924,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.flags.incl nfIsRef
else:
stackTrace(c, tos, pc, "node is not a symbol")
of opcGetImplTransf:
decodeB(rkNode)
let a = regs[rb].node
if a.kind == nkSym:
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
else:
let ast = a.sym.ast.shallowCopy
for i in 0..<a.sym.ast.len:
ast[i] = a.sym.ast[i]
ast[bodyPos] = transformBody(c.graph, a.sym)
ast.copyTree()
of opcSymOwner:
decodeB(rkNode)
let a = regs[rb].node

View File

@@ -107,6 +107,7 @@ type
opcEqIdent,
opcStrToIdent,
opcGetImpl,
opcGetImplTransf
opcEcho,
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...

View File

@@ -29,7 +29,7 @@
import
strutils, ast, astalgo, types, msgs, renderer, vmdef,
trees, intsets, magicsys, options, lowerings, lineinfos
trees, intsets, magicsys, options, lowerings, lineinfos, transf
import platform
from os import splitFile
@@ -1122,6 +1122,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mStaticExec: genBinaryABCD(c, n, dest, opcGorge)
of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag)
of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
of mGetImplTransf: genUnaryABC(c, n, dest, opcGetImplTransf)
of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner)
of mNChild: genBinaryABC(c, n, dest, opcNChild)
of mNSetChild: genVoidABC(c, n, dest, opcNSetChild)
@@ -2129,7 +2130,7 @@ proc genProc(c: PCtx; s: PSym): int =
s.ast.sons[miscPos] = x
# thanks to the jmp we can add top level statements easily and also nest
# procs easily:
let body = s.getBody
let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s))
let procStart = c.xjmp(body, opcJmp, 0)
var p = PProc(blocks: @[], sym: s)
let oldPrc = c.prc

View File

@@ -252,6 +252,10 @@ else: # bootstrapping substitute
else:
n.strValOld
when defined(nimSymImplTransform):
proc getImplTransformed*(symbol: NimNode): NimNode {.magic: "GetImplTransf", noSideEffect.}
## for a typed proc returns the AST after transformation pass
when defined(nimHasSymOwnerInMacro):
proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
## accepts node of kind nnkSym and returns its owner's symbol.

View File

@@ -118,13 +118,13 @@ when defined(memProfiler):
var
gTicker {.threadvar.}: int
proc requestedHook(): bool {.nimcall.} =
proc requestedHook(): bool {.nimcall, locks: 0.} =
if gTicker == 0:
gTicker = SamplingInterval
result = true
dec gTicker
proc hook(st: StackTrace, size: int) {.nimcall.} =
proc hook(st: StackTrace, size: int) {.nimcall, locks: 0.} =
when defined(ignoreAllocationSize):
hookAux(st, 1)
else:
@@ -136,7 +136,7 @@ else:
gTicker: int # we use an additional counter to
# avoid calling 'getTicks' too frequently
proc requestedHook(): bool {.nimcall.} =
proc requestedHook(): bool {.nimcall, locks: 0.} =
if interval == 0: result = true
elif gTicker == 0:
gTicker = 500
@@ -145,7 +145,7 @@ else:
else:
dec gTicker
proc hook(st: StackTrace) {.nimcall.} =
proc hook(st: StackTrace) {.nimcall locks: 0.} =
#echo "profiling! ", interval
if interval == 0:
hookAux(st, 1)

View File

@@ -1,12 +1,7 @@
discard """
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
cmd: "nim check --hint[Performance]:off $file"
nimout: '''
tprevent_assign2.nim(53, 31) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(52, 13)
tprevent_assign2.nim(55, 31) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(52, 13)
tprevent_assign2.nim(66, 29) Error: '=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(68, 9)
'''
file: "tprevent_assign2.nim"
line: 48
"""
type
@@ -56,13 +51,5 @@ proc preventThis() =
else:
discard
proc preventThis2() =
var otherTree: Foo
try:
try:
otherTree = createTree(44)
echo otherTree
finally:
take2(createTree(34), otherTree)
finally:
echo otherTree
allowThis()
preventThis()

View File

@@ -0,0 +1,53 @@
discard """
errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
file: "tprevent_assign3.nim"
line: 46
"""
type
Foo = object
x: int
proc `=destroy`(f: var Foo) = f.x = 0
proc `=`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
proc createTree(x: int): Foo =
Foo(x: x)
proc take2(a, b: sink Foo) =
echo a.x, " ", b.x
proc allowThis() =
var otherTree: Foo
try:
for i in 0..3:
while true:
#if i == 0:
otherTree = createTree(44)
case i
of 0:
echo otherTree
take2(createTree(34), otherTree)
of 1:
take2(createTree(34), otherTree)
else:
discard
finally:
discard
proc preventThis2() =
var otherTree: Foo
try:
try:
otherTree = createTree(44)
echo otherTree
finally:
take2(createTree(34), otherTree)
finally:
echo otherTree
allowThis()
preventThis2()

View File

@@ -94,7 +94,7 @@ proc fn3(x, y: int): bool =
static:
let fn1s = "proc fn1(x, y: int): int =\n result = 2 * (x + y)\n"
let fn2s = "proc fn2(x, y: float): float =\n result = (y + 2.0 * x) / (x - y)\n"
let fn2s = "proc fn2(x, y: float): float =\n result = (y + 2 * x) / (x - y)\n"
let fn3s = "proc fn3(x, y: int): bool =\n result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n"
doAssert fn1.repr_to_string == fn1s
doAssert fn2.repr_to_string == fn2s