-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
transf: lower all unlabeled break
statements
#918
transf: lower all unlabeled break
statements
#918
Conversation
`liftForLoop` was emitting an unlabeld `nkBreakStmt` for exiting the loop. The procedure now gets passed the loop's enclosing block's label, which allows it to emit a labeled `nkBreakStmt` instead.
Instead of happening in `mirgen`, all `while` loops are now transformed into roughly: ```nim while true: if not cond: break body ``` during `transf`. This means that the `closureiters` transformation doesn't has to, which in turn removes the only source of `nkBreakStmt` nodes with no label.
The `closureiters` transformation doesn't support `nkYieldStmt`s appearing within `if`/`elif` statements/expressions, so just placing the `nkWhileStmt`s condition expression into an `nkIfStmt` introduces a regression.
With all 'break's coming out of `transf` having labels, the MIR doesn't have to support unlabeled ones anymore. Most notably, this means that: - `LabelId` doesn't need a sentinel value - the control-flow-graph computation becomes simpler
With all 'break' statement coming out of the MIR phase using labels, the CG IR doesn't have to support unlabeled ones. This simplifies all three code generators, with the JS and C one being affected the most. For the JS target, this also has the effect of less code being generated for `while` statements.
The transformations no longer need to support: - unlabeled breaks - `while` statements with complex condition expressions Since `nkContinueStmt`s and now unlabeled `nkBreakStmt`s no longer reach `closureiters`, `transformBreaksAndContinuesInWhile` becomes obsolete and is thus removed.
With unlabeled breaks removed from the MIR, the `while true: break` has to be updated to use a labeled break.
Since all elements in the `blocks` list have a label now, the label can be stored there directly, instead of going through the `PNode` indirection.
My plan is to eventually turn the For the extraneous |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The increased regularity of the code is really good, it's silly looking at how much code was just devoted to carrying around that ambiguity.
scope(c.stmts): | ||
c.gen(n[1]) | ||
|
||
c.stmts.add endNode(mnkRepeat) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, due to the simpler generation the need for bookending with the endNode
drops too, cool.
Co-authored-by: Saem Ghani <saemghani+github@gmail.com>
/merge |
Merge requested by: @saem Contents after the first section break of the PR description has been removed and preserved below:
|
Summary
Fix the cases where unlabeled
break
statements were inserted bytransf
, which means that unlabeledbreak
statements now no longerexist after the main
transf
pass. This allows for:break
support from the MIR andCgNode
IRclosureiters
transformationReplacing
skLabel
usage in the code generators also becomes easier.Details
Since they're directly associated with a
block
, labeledbreak
statements are easier to handle for analysis and code generation. For
this reason,
transf
already transforms all unlabeledbreak
statements into labeled ones, by:
block
s that don't have a user-provided onewhile
andfor
statements with namedblock
sHowever, there were two occurrences where unlabeled
break
statements(
(nkBreakStmt (nkEmpty))
) were injected bytransf
:for
statements of closure iterators (liftForLoop
)closureiters
transformation when turningwhile cond
loopsinto
while true
loops (although not strictly part oftransf
)As a consequence, unlabeled
break
reached all the way into the codegenerators, requiring dedicated support by the MIR, MIR processing, and
code generation.
While
mirgen
could lower unlabeledbreak
statements, the associationof a
while
to its surrounding injectedblock
no longer exists, andmirgen
is generally not well suited for non-local (i.e., not applyingto a single node) transformations.
Instead, the occurrences where unlabeled
break
statements are insertedare adjusted. For the
for
statement, the label of the wrapper-block ispassed to
liftForLoop
, where the injectednkBreakStmt
can then useit. However, for the other occurrence, a more complex solution is
needed.
Since the
while
lowering theclosureiters
pass conditionally applies(which is where the unlabeled
break
is injected) is the same as theone
mirgen
automatically applies when generatingrepeat
statements,the transformation from
mirgen.genWhile
is turned into aPNode
-basedtransformation that is applied in
transf.transformWhile
. Some extraadjustments are required:
PNode
doesn't have a dedicated "scope" construct like the MIR does.It is emulated via a
nkBlockStmt
yield
statementswithin
if
/elif
conditions, so directly placing the formerwhile
condition into an
if
condition would regress onyield
support. Priorto placing the expression into the
if
condition,nkStmtListExpr
sare thus first unpacked into the loop body
Only
while true
loops exist after the maintransf
pass now.closureiters
simplificationsMultiple simplifications are possible now that neither unlabeled
break
s norwhile
loops with non-true
-literal conditions existat the point when the
closureiters
pass is run.transformBreaksAndContinuesInWhile
, which handled unlabeledbreak
s andcontinue
statements inwhile
loopsnkWhileStmt
s (lowerStmtListExprs
)nkWhileStmt
condition handling from the to-basic-blocktransformation (
transformClosureIteratorBody
)nkWhileStmt
handling from preprocessing (preprocess
)MIR simplifications
LabelId
; all breaksin the MIR are labeled now
(
mirexec
andcgirgen
)Code generator simplifications
Each code generator required special handling for associating unlabeled
break
s with their targeted construct (while
orblock
), withcgen
andjsgen
being affected the most. All of it is removed.As a side effect, the output of
jsgen
for loops slightly improves: noextra
Label:
is emitted around everywhile
.