diff options
author | Saem Ghani <saemghani+github@gmail.com> | 2021-03-02 01:32:43 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-02 10:32:43 +0100 |
commit | ab780f66ef67ea0333278d75e4af064bcae71c57 (patch) | |
tree | e7f778e6a92d12803c7cb8c68e432d0eecdd045b /compiler/dfa.nim | |
parent | 33833968c46dd3a5dc8c379abdb7021b0d304b7f (diff) | |
download | Nim-ab780f66ef67ea0333278d75e4af064bcae71c57.tar.gz |
fixes #17198, DFA failure on large case stmts (#17210)
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.
Diffstat (limited to 'compiler/dfa.nim')
-rw-r--r-- | compiler/dfa.nim | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 517d13831..c7a9d4694 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -455,6 +455,10 @@ proc genCase(c: var Con; n: PNode) = let isExhaustive = skipTypes(n[0].typ, 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] = @[] c.gen(n[0]) 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): # treat the last branch as 'else' if this is an exhaustive case statement. c.gen(it.lastSon) + if endings.len != 0: + c.patch(endings[^1]) else: forkT(it.lastSon): c.gen(it.lastSon) + if endings.len != 0: + c.patch(endings[^1]) 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) = withBlock(n[0].sym): |