This alters the DFA control flow graph generation for case statments. Gotos are now generated as a chained link, this ensures that evaluation of variant branches collapses as early as possible, without hitting the 2k call limit.
This commit is contained in:
parent
33833968c4
commit
ab780f66ef
2 changed files with 40 additions and 3 deletions
|
|
@ -455,6 +455,10 @@ proc genCase(c: var Con; n: PNode) =
|
||||||
let isExhaustive = skipTypes(n[0].typ,
|
let isExhaustive = skipTypes(n[0].typ,
|
||||||
abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString}
|
abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString}
|
||||||
|
|
||||||
|
# we generate endings as a set of chained gotos, this is a bit awkward but it
|
||||||
|
# ensures when recursively traversing the CFG for various analysis, we don't
|
||||||
|
# artificially extended the life of each branch (for the purposes of DFA)
|
||||||
|
# beyond the minimum amount.
|
||||||
var endings: seq[TPosition] = @[]
|
var endings: seq[TPosition] = @[]
|
||||||
c.gen(n[0])
|
c.gen(n[0])
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
|
|
@ -462,13 +466,14 @@ proc genCase(c: var Con; n: PNode) =
|
||||||
if it.len == 1 or (i == n.len-1 and isExhaustive):
|
if it.len == 1 or (i == n.len-1 and isExhaustive):
|
||||||
# treat the last branch as 'else' if this is an exhaustive case statement.
|
# treat the last branch as 'else' if this is an exhaustive case statement.
|
||||||
c.gen(it.lastSon)
|
c.gen(it.lastSon)
|
||||||
|
if endings.len != 0:
|
||||||
|
c.patch(endings[^1])
|
||||||
else:
|
else:
|
||||||
forkT(it.lastSon):
|
forkT(it.lastSon):
|
||||||
c.gen(it.lastSon)
|
c.gen(it.lastSon)
|
||||||
|
if endings.len != 0:
|
||||||
|
c.patch(endings[^1])
|
||||||
endings.add c.gotoI(it.lastSon)
|
endings.add c.gotoI(it.lastSon)
|
||||||
for i in countdown(endings.high, 0):
|
|
||||||
let endPos = endings[i]
|
|
||||||
c.patch(endPos)
|
|
||||||
|
|
||||||
proc genBlock(c: var Con; n: PNode) =
|
proc genBlock(c: var Con; n: PNode) =
|
||||||
withBlock(n[0].sym):
|
withBlock(n[0].sym):
|
||||||
|
|
|
||||||
32
tests/destructor/t17198.nim
Normal file
32
tests/destructor/t17198.nim
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
discard """
|
||||||
|
cmd: '''nim c --gc:arc $file'''
|
||||||
|
output: '''
|
||||||
|
other
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import std/macros
|
||||||
|
|
||||||
|
macro bigCaseStmt(arg: untyped): untyped =
|
||||||
|
result = nnkCaseStmt.newTree(arg)
|
||||||
|
|
||||||
|
# try to change 2000 to a bigger value if it doesn't crash
|
||||||
|
for x in 0 ..< 2000:
|
||||||
|
result.add nnkOfBranch.newTree(newStrLitNode($x), newStrLitNode($x))
|
||||||
|
|
||||||
|
result.add nnkElse.newTree(newStrLitNode("other"))
|
||||||
|
|
||||||
|
macro bigIfElseExpr(): untyped =
|
||||||
|
result = nnkIfExpr.newTree()
|
||||||
|
|
||||||
|
for x in 0 ..< 1000:
|
||||||
|
result.add nnkElifExpr.newTree(newLit(false), newStrLitNode($x))
|
||||||
|
|
||||||
|
result.add nnkElseExpr.newTree(newStrLitNode("other"))
|
||||||
|
|
||||||
|
proc test(arg: string): string =
|
||||||
|
echo bigIfElseExpr()
|
||||||
|
|
||||||
|
result = bigCaseStmt(arg)
|
||||||
|
|
||||||
|
discard test("test")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue