This commit is contained in:
Araq 2020-07-08 10:03:09 +02:00 • committed by Andreas Rumpf
commit ecf8cbbbe0
2 changed files with 62 additions and 38 deletions

View file

@ -41,6 +41,30 @@ type
# means that 'x' escapes. We then destroy it # means that 'x' escapes. We then destroy it
# in the parent's scope (and also allocate it there). # in the parent's scope (and also allocate it there).
type
Con = object
owner: PSym
g: ControlFlowGraph
jumpTargets: IntSet
destroys, topLevelVars: PNode
graph: ModuleGraph
emptyNode: PNode
otherRead: PNode
inLoop, inSpawn: int
uninit: IntSet # set of uninit'ed vars
uninitComputed: bool
ProcessMode = enum
normal
consumed
sinkArg
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info)
sym.typ = typ
s.vars.add(sym)
result = newSymNode(sym)
proc nestedScope(parent: var Scope): Scope = proc nestedScope(parent: var Scope): Scope =
Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent)) Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent))
@ -99,7 +123,7 @@ type
onlyCareAboutVars, onlyCareAboutVars,
producesValue producesValue
proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode = proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode =
if not s.needsTry: optimize(s) if not s.needsTry: optimize(s)
assert ret != nil assert ret != nil
if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0: if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0:
@ -107,8 +131,11 @@ proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode =
result = ret result = ret
else: else:
let isExpr = producesValue in flags and not isEmptyType(ret.typ) let isExpr = producesValue in flags and not isEmptyType(ret.typ)
var r = PNode(nil)
if isExpr: if isExpr:
result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) result = newNodeIT(nkStmtListExpr, ret.info, ret.typ)
if ret.kind == nkStmtListExpr:
r = getTemp(c, s, ret.typ, ret.info)
else: else:
result = newNodeI(nkStmtList, ret.info) result = newNodeI(nkStmtList, ret.info)
@ -126,32 +153,15 @@ proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode =
for m in s.wasMoved: finSection.add m for m in s.wasMoved: finSection.add m
for i in countdown(s.final.high, 0): finSection.add s.final[i] for i in countdown(s.final.high, 0): finSection.add s.final[i]
result.add newTryFinally(ret, finSection) result.add newTryFinally(ret, finSection)
elif isExpr:
for m in s.wasMoved: result.add m
for i in countdown(s.final.high, 0): result.add s.final[i]
result.add ret
else: else:
result.add ret if r != nil:
result.add newTree(nkFastAsgn, r, ret)
else:
result.add ret
for m in s.wasMoved: result.add m for m in s.wasMoved: result.add m
for i in countdown(s.final.high, 0): result.add s.final[i] for i in countdown(s.final.high, 0): result.add s.final[i]
if r != nil:
type result.add r
Con = object
owner: PSym
g: ControlFlowGraph
jumpTargets: IntSet
destroys, topLevelVars: PNode
graph: ModuleGraph
emptyNode: PNode
otherRead: PNode
inLoop, inSpawn: int
uninit: IntSet # set of uninit'ed vars
uninitComputed: bool
ProcessMode = enum
normal
consumed
sinkArg
const toDebug {.strdefine.} = "" const toDebug {.strdefine.} = ""
@ -409,12 +419,6 @@ proc addTopVar(c: var Con; s: var Scope; v: PNode): ptr Scope =
result = result.parent result = result.parent
result[].vars.add v.sym result[].vars.add v.sym
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info)
sym.typ = typ
s.vars.add(sym)
result = newSymNode(sym)
proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
# discriminator is ordinal value that doesn't need sink destroy # discriminator is ordinal value that doesn't need sink destroy
# but fields within active case branch might need destruction # but fields within active case branch might need destruction
@ -661,7 +665,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
var ofScope = nestedScope(s) var ofScope = nestedScope(s)
markEscapingVars(it[^1], ofScope) markEscapingVars(it[^1], ofScope)
let ofResult = maybeVoid(it[^1], ofScope) let ofResult = maybeVoid(it[^1], ofScope)
branch[^1] = toTree(ofScope, ofResult, treeFlags) branch[^1] = toTree(c, ofScope, ofResult, treeFlags)
result.add branch result.add branch
rememberParent(s, ofScope) rememberParent(s, ofScope)
@ -671,7 +675,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
result.add p(n[0], c, s, normal) result.add p(n[0], c, s, normal)
var bodyScope = nestedScope(s) var bodyScope = nestedScope(s)
let bodyResult = p(n[1], c, bodyScope, normal) let bodyResult = p(n[1], c, bodyScope, normal)
result.add toTree(bodyScope, bodyResult, treeFlags) result.add toTree(c, bodyScope, bodyResult, treeFlags)
rememberParent(s, bodyScope) rememberParent(s, bodyScope)
dec c.inLoop dec c.inLoop
@ -682,7 +686,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
var bodyScope = nestedScope(s) var bodyScope = nestedScope(s)
markEscapingVars(n[1], bodyScope) markEscapingVars(n[1], bodyScope)
let bodyResult = processCall(n[1], bodyScope) let bodyResult = processCall(n[1], bodyScope)
result.add toTree(bodyScope, bodyResult, treeFlags) result.add toTree(c, bodyScope, bodyResult, treeFlags)
rememberParent(s, bodyScope) rememberParent(s, bodyScope)
of nkIfStmt, nkIfExpr: of nkIfStmt, nkIfExpr:
@ -695,12 +699,12 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
branchScope.parent = nil branchScope.parent = nil
if it.kind in {nkElifBranch, nkElifExpr}: if it.kind in {nkElifBranch, nkElifExpr}:
let cond = p(it[0], c, branchScope, normal) let cond = p(it[0], c, branchScope, normal)
branch[0] = toTree(branchScope, cond, {producesValue, onlyCareAboutVars}) branch[0] = toTree(c, branchScope, cond, {producesValue, onlyCareAboutVars})
branchScope.parent = addr(s) branchScope.parent = addr(s)
markEscapingVars(it[^1], branchScope) markEscapingVars(it[^1], branchScope)
var branchResult = processCall(it[^1], branchScope) var branchResult = processCall(it[^1], branchScope)
branch[^1] = toTree(branchScope, branchResult, treeFlags) branch[^1] = toTree(c, branchScope, branchResult, treeFlags)
result.add branch result.add branch
rememberParent(s, branchScope) rememberParent(s, branchScope)
@ -710,7 +714,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
var tryScope = nestedScope(s) var tryScope = nestedScope(s)
markEscapingVars(n[0], tryScope) markEscapingVars(n[0], tryScope)
var tryResult = maybeVoid(n[0], tryScope) var tryResult = maybeVoid(n[0], tryScope)
result.add toTree(tryScope, tryResult, treeFlags) result.add toTree(c, tryScope, tryResult, treeFlags)
rememberParent(s, tryScope) rememberParent(s, tryScope)
for i in 1..<n.len: for i in 1..<n.len:
@ -719,7 +723,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
var branchScope = nestedScope(s) var branchScope = nestedScope(s)
var branchResult = if it.kind == nkFinally: p(it[^1], c, branchScope, normal) var branchResult = if it.kind == nkFinally: p(it[^1], c, branchScope, normal)
else: processCall(it[^1], branchScope) else: processCall(it[^1], branchScope)
branch[^1] = toTree(branchScope, branchResult, treeFlags) branch[^1] = toTree(c, branchScope, branchResult, treeFlags)
result.add branch result.add branch
rememberParent(s, branchScope) rememberParent(s, branchScope)
@ -1120,7 +1124,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
scope.final.add genDestroy(c, params[i]) scope.final.add genDestroy(c, params[i])
#if optNimV2 in c.graph.config.globalOptions: #if optNimV2 in c.graph.config.globalOptions:
# injectDefaultCalls(n, c) # injectDefaultCalls(n, c)
result = toTree(scope, body, {}) result = toTree(c, scope, body, {})
dbg: dbg:
echo ">---------transformed-to--------->" echo ">---------transformed-to--------->"
echo renderTree(result, {renderIds}) echo renderTree(result, {renderIds})

View file

@ -12,6 +12,7 @@ if
end true end true
7 7
##index 2 not in 0 .. 1## ##index 2 not in 0 .. 1##
true
''' '''
cmd: "nim c --gc:arc -d:danger $file" cmd: "nim c --gc:arc -d:danger $file"
""" """
@ -102,3 +103,22 @@ proc escapeCheck =
clItems(toSeq()) clItems(toSeq())
escapeCheck() escapeCheck()
# bug #14900
template sortedByIt(seq1): untyped =
var result = seq1
result
proc seqsEqual(seq1, seq2: seq[string]): bool =
# works as a normal proc (if we would assign result inside)
# doesn't work as an expression
result = if false: # needed
false
else:
let a1 = seq1.sortedByIt()
let a2 = seq2.sortedByIt()
# echo a1 - works if you uncomment any of these
# echo a2
a1 == a2
echo seqsEqual(@["a", "b", "c"], @["a", "b", "c"])