153
153
body: PNode
154
154
excLandingState: PNode # label of exception landing state (except or finally)
155
155
inlinable: bool
156
+ deletable: bool
156
157
157
158
Ctx = object
158
159
g: ModuleGraph
162
163
curExcLevelSym: PSym # Current exception
163
164
164
165
# states: seq[tuple[label: PNode, body: PNode, inlinable: bool]] # The resulting states. Label is int literal.
166
+ uninlinableStates: seq [PNode] # List of state labels that must not be inlined
165
167
states: seq [State] # The resulting states. Label is int literal.
166
168
finallyPathStack: seq [FinallyTarget] # nkWhileStmt, nkBlock, nkTryStmt
167
169
stateLoopLabel: PSym # Label to break on, when jumping between states.
@@ -254,7 +256,7 @@ proc newCurExcLevelAccess(ctx: var Ctx): PNode =
254
256
proc newStateLabel(ctx: Ctx): PNode =
255
257
ctx.g.newIntLit(TLineInfo(), 0 )
256
258
257
- proc newState1 (ctx: var Ctx, n: PNode, inlinable: bool , label: PNode): PNode =
259
+ proc newState (ctx: var Ctx, n: PNode, inlinable: bool , label: PNode): PNode =
258
260
# Creates a new state, adds it to the context
259
261
# Returns label of the newly created state
260
262
@@ -896,6 +898,8 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
896
898
# :state = :env.finallyPath[curFinallyLevel_const]
897
899
898
900
let nextState = ctx.newFinallyPathAccess(ctx.curFinallyLevel, info)
901
+ let exitFinally = newTree(nkGotoState, nextState)
902
+
899
903
let cmpStateToZero = newTreeIT(nkCall,
900
904
info, ctx.g.getSysType(info, tyBool),
901
905
newSymNode(ctx.g.getSysMagic(info, " ==" , mEqI), info),
@@ -921,7 +925,6 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
921
925
newTree(nkReturnStmt, retValue)
922
926
retStmt.flags.incl(nfNoRewrite)
923
927
924
- let exitFinally = newTree(nkGotoState, nextState)
925
928
926
929
let ifBody = newTree(nkIfStmt,
927
930
newTree(nkElifBranch, excNilCmp, retStmt),
@@ -932,7 +935,8 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
932
935
933
936
result = newTree(nkIfStmt,
934
937
newTreeI(nkElifBranch, info, cmpStateToZero, ifBody),
935
- newTreeI(nkElse, info, exitFinally))
938
+ # newTreeI(nkElse, info, exitFinally)
939
+ )
936
940
937
941
938
942
proc newJumpAlongFinallyChain(ctx: var Ctx, finallyChain: seq [PNode], info: TLineInfo) : PNode =
@@ -975,9 +979,10 @@ proc transformBreakStmt(ctx: var Ctx, n: PNode): PNode =
975
979
elif b.kind == nkFinally:
976
980
finallyChain.add(ctx.finallyPathStack[i].enterLabel)
977
981
978
- assert(finallyChain.len > 0 )
979
-
980
- result = ctx.newJumpAlongFinallyChain(finallyChain, n.info)
982
+ if finallyChain.len > 0 :
983
+ result = ctx.newJumpAlongFinallyChain(finallyChain, n.info)
984
+ else :
985
+ result = n
981
986
982
987
proc transformContinueStmt(ctx: var Ctx, n: PNode): PNode =
983
988
# "Continuing" involves finding the corresponding target state in finallyPathStack,
@@ -1072,17 +1077,18 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
1072
1077
s.add(n[j])
1073
1078
1074
1079
n.sons.setLen(i + 1 )
1075
- discard ctx.newState1 (s, true , label)
1080
+ discard ctx.newState (s, true , label)
1076
1081
if ctx.transformClosureIteratorBody(s, gotoOut) != s:
1077
1082
internalError(ctx.g.config, " transformClosureIteratorBody != s" )
1078
1083
break
1079
1084
else :
1080
1085
n[i] = ctx.transformBreaksContinuesAndReturns(n[i])
1081
1086
1082
1087
of nkYieldStmt:
1083
- result = newNodeI(nkStmtList, n.info)
1084
- result .add(n)
1085
- result .add(gotoOut)
1088
+ result = addGotoOut(result , gotoOut)
1089
+ # result = newNodeI(nkStmtList, n.info)
1090
+ # result.add(n)
1091
+ # result.add(gotoOut)
1086
1092
1087
1093
of nkElse, nkElseExpr:
1088
1094
result [0 ] = addGotoOut(result [0 ], gotoOut)
@@ -1115,7 +1121,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
1115
1121
# result = newNodeI(nkGotoState, n.info)
1116
1122
1117
1123
let s = newNodeI(nkStmtList, n.info)
1118
- let enterLabel = ctx.newState1 (s, false , nil )
1124
+ let enterLabel = ctx.newState (s, false , nil )
1119
1125
1120
1126
let ifNode = newNodeI(nkIfStmt, n.info)
1121
1127
let elifBranch = newNodeI(nkElifBranch, n.info)
@@ -1190,7 +1196,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
1190
1196
elif finallyBody.kind != nkEmpty: finallyLabel
1191
1197
else : oldExcLandingState
1192
1198
# ctx.curExcHandlingState = exceptIdx
1193
- discard ctx.newState1 (tryBody, false , tryLabel)
1199
+ discard ctx.newState (tryBody, false , tryLabel)
1194
1200
# assert(realTryIdx.intVal == tryIdx)
1195
1201
1196
1202
if finallyBody.kind != nkEmpty:
@@ -1203,7 +1209,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
1203
1209
if exceptBody.kind != nkEmpty:
1204
1210
ctx.curExcLandingState = if finallyBody.kind != nkEmpty: finallyLabel
1205
1211
else : oldExcLandingState
1206
- discard ctx.newState1 (exceptBody, false , exceptLabel)
1212
+ discard ctx.newState (exceptBody, false , exceptLabel)
1207
1213
# assert(realExceptIdx.intVal == -exceptIdx)
1208
1214
1209
1215
let normalOut = if finallyBody.kind != nkEmpty: gotoOut else : nil
@@ -1216,8 +1222,9 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
1216
1222
1217
1223
if finallyBody.kind != nkEmpty:
1218
1224
discard ctx.finallyPathStack.pop()
1219
- discard ctx.newState1(finallyBody, false , finallyLabel)
1220
- if ctx.transformClosureIteratorBody(finallyBody, gotoOut) != finallyBody:
1225
+ discard ctx.newState(finallyBody, false , finallyLabel)
1226
+ let finallyExit = newTree(nkGotoState, ctx.newFinallyPathAccess(ctx.curFinallyLevel - 1 , finallyBody.info))
1227
+ if ctx.transformClosureIteratorBody(finallyBody, finallyExit) != finallyBody:
1221
1228
internalError(ctx.g.config, " transformClosureIteratorBody != finallyBody" )
1222
1229
dec ctx.curFinallyLevel
1223
1230
@@ -1490,27 +1497,119 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
1490
1497
blockStmt.add(blockBody)
1491
1498
loopBody.add(blockStmt)
1492
1499
1493
- proc countStateOccurences(n: PNode, stateOccurences: var openArray [int ]) =
1500
+ proc countStateOccurences(ctx: var Ctx, n: PNode, stateOccurences: var openArray [int ]) =
1494
1501
# # Find all nkGotoState(stateIdx) nodes that do not follow nkYield.
1495
1502
# # For every such node increment stateOccurences[stateIdx]
1496
1503
for i, c in n:
1497
- if c.kind == nkGotoState and (i == 0 or n[i - 1 ].kind != nkYieldStmt):
1504
+ if c.kind == nkGotoState and c[ 0 ].kind == nkIntLit and (i > 0 and n[i - 1 ].kind != nkYieldStmt):
1498
1505
let stateIdx = c[0 ].intVal
1499
1506
if stateIdx >= 0 :
1500
1507
inc stateOccurences[stateIdx]
1508
+ elif c.kind == nkIntLit:
1509
+ let idx = c.intVal
1510
+ if idx >= 0 and idx < ctx.states.len and ctx.states[idx].label == c:
1511
+ ctx.states[idx].inlinable = false
1501
1512
else :
1502
- countStateOccurences(c, stateOccurences)
1513
+ ctx.countStateOccurences(c, stateOccurences)
1514
+
1515
+ proc replaceDeletedStates(ctx: var Ctx, n: PNode): PNode =
1516
+ result = n
1517
+ for i in 0 ..< n.safeLen:
1518
+ let c = n[i]
1519
+ if c.kind == nkIntLit:
1520
+ let idx = c.intVal
1521
+ if idx >= 0 and idx < ctx.states.len and ctx.states[idx].label == c and ctx.states[idx].deletable:
1522
+ let ns = ctx.replaceDeletedStates(ctx.states[idx].body)
1523
+ assert(ns.kind == nkStmtList and ns.len == 1 and ns[0 ].kind == nkGotoState and ns[0 ][0 ].kind == nkIntLit)
1524
+ n[i] = ns[0 ][0 ]
1525
+ else :
1526
+ n[i] = ctx.replaceDeletedStates(c)
1527
+
1528
+ proc replaceInlinedStates(ctx: var Ctx, n: PNode): PNode =
1529
+ # # Find all nkGotoState(stateIdx) nodes that do not follow nkYield.
1530
+ # # For every such node increment stateOccurences[stateIdx]
1531
+ result = n
1532
+ for i in 0 ..< n.safeLen:
1533
+ let c = n[i]
1534
+ if c.kind == nkGotoState and c[0 ].kind == nkIntLit and (i > 0 and n[i - 1 ].kind != nkYieldStmt):
1535
+ let stateIdx = c[0 ].intVal
1536
+ if stateIdx >= 0 :
1537
+ if ctx.states[stateIdx].inlinable:
1538
+ n[i] = ctx.states[stateIdx].body
1539
+ else :
1540
+ n[i] = ctx.replaceInlinedStates(c)
1541
+
1503
1542
1504
1543
proc deleteEmptyStates(ctx: var Ctx) =
1544
+ # 1. Assign temporary indexes to state labels to facilitate
1545
+ # countStateOccurences. Label number will correspond to index in
1546
+ # ctx.states
1547
+
1548
+ # for i in 0 .. ctx.states.high:
1549
+ # ctx.states[i].label.intVal = i
1550
+
1551
+ # 1. Delete empty states: go through ctx.states,
1552
+ # if a state consists only of gotoState node, delete it from states
1553
+ # and replace its label index to its target state
1554
+
1555
+ # var labelsToReplace = newSeq[(PNode, PNode, bool)]()
1556
+
1557
+ # Collect empty states
1558
+ for i in 0 .. ctx.states.high:
1559
+ let s = ctx.states[i]
1560
+ let body = skipStmtList(s.body)
1561
+ if body.kind == nkGotoState and body[0 ].kind == nkIntLit and body[0 ].intVal >= 0 :
1562
+ ctx.states[i].deletable = true
1563
+
1564
+ # Delete empty states
1565
+ for i in 0 .. ctx.states.high:
1566
+ ctx.states[i].body = ctx.replaceDeletedStates(ctx.states[i].body)
1567
+
1568
+ # Remove deletable states
1569
+ var i = 0
1570
+ while i < ctx.states.len:
1571
+ if ctx.states[i].deletable:
1572
+ ctx.states.delete(i)
1573
+ else :
1574
+ inc i
1575
+
1576
+ # Reassign state label indexes
1577
+ for i in 0 .. ctx.states.high:
1578
+ ctx.states[i].label.intVal = i
1579
+
1580
+ # 2. Count state occurences
1505
1581
var stateOccurences = newSeq[int ](ctx.states.len)
1506
1582
for s in ctx.states:
1507
- countStateOccurences(s.body, stateOccurences)
1508
- echo " StateOccurences: " , stateOccurences
1583
+ ctx. countStateOccurences(s.body, stateOccurences)
1584
+
1509
1585
var statesToInline = newSeq[int ]()
1510
1586
for i, o in stateOccurences:
1511
1587
if o == 1 and ctx.states[i].inlinable:
1512
- statesToInline.add(i)
1513
- echo " States to inline: " , statesToInline
1588
+ discard
1589
+ else :
1590
+ ctx.states[i].inlinable = false
1591
+ # statesToInline.add(i)
1592
+
1593
+ # echo "States to optimize:"
1594
+ # for i, s in ctx.states:
1595
+ # if s.deletable: echo i, ": delete"
1596
+ # elif s.inlinable: echo i, ": inline"
1597
+
1598
+ # Inline states
1599
+ for i in 0 .. ctx.states.high:
1600
+ ctx.states[i].body = ctx.replaceInlinedStates(ctx.states[i].body)
1601
+
1602
+ # Remove inlined states
1603
+ i = 0
1604
+ while i < ctx.states.len:
1605
+ if ctx.states[i].inlinable:
1606
+ ctx.states.delete(i)
1607
+ else :
1608
+ inc i
1609
+
1610
+ # Reassign state label indexes
1611
+ for i in 0 .. ctx.states.high:
1612
+ ctx.states[i].label.intVal = i
1514
1613
1515
1614
# proc deleteEmptyStates(ctx: var Ctx) =
1516
1615
# let goOut = newTree(nkGotoState, ctx.g.newIntLit(TLineInfo(), -1))
@@ -1625,7 +1724,7 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
1625
1724
var n = n.toStmtList
1626
1725
# echo "transformed into ", n
1627
1726
1628
- discard ctx.newState1 (n, false , nil )
1727
+ discard ctx.newState (n, false , nil )
1629
1728
let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, - 1 ))
1630
1729
1631
1730
var ns = false
@@ -1638,13 +1737,13 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
1638
1737
# Splitting transformation
1639
1738
discard ctx.transformClosureIteratorBody(n, gotoOut)
1640
1739
1641
- # Optimize empty states away
1642
- # ctx.deleteEmptyStates()
1643
-
1644
1740
# Assign state label indexes
1645
1741
for i in 0 .. ctx.states.high:
1646
1742
ctx.states[i].label.intVal = i
1647
1743
1744
+ # Optimize empty states away
1745
+ ctx.deleteEmptyStates()
1746
+
1648
1747
let caseDispatcher = newTreeI(nkCaseStmt, n.info,
1649
1748
ctx.newStateAccess())
1650
1749
@@ -1662,11 +1761,11 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
1662
1761
result = liftLocals(ctx, result )
1663
1762
1664
1763
when false :
1665
- echo " TRANSFORM TO STATES: "
1764
+ echo " TRANSFORM TO STATES:"
1666
1765
echo renderTree(result )
1667
1766
1668
1767
# echo "exception table:"
1669
1768
# for i, s in ctx.states:
1670
1769
# echo i, " -> ", s.excLandingState
1671
1770
1672
- echo " ENV: " , renderTree(getEnvParam(fn).typ.elementType.n)
1771
+ # echo "ENV: ", renderTree(getEnvParam(fn).typ.elementType.n)
0 commit comments