instructor: Prof. Dr. Peter Thiemann date: 2024-05-14 title: Chapter 5
Conditionals
Changes to the transformation pipeline
Shrink
- remove
and
andor
in favor of conditional expression
if not cond: sethen else: seelse
--->
if cond: seelse else: sethen
Transformation to monadic form
output grammar ast_ir_mon
type ExprAtom = EConst | EVar
type Expr = ExprAtom | EOp1 | EOp2 | EInput | ECompare
type Stmt = SPrint | SAssign | SCond
type Program = IList[Stmt]
- expression conditional eliminated
- arguments to
EOp1
,EOp2
,ECompare
, andSPrint
are atomic - expression arguments to
SAssign
,SCond
are not atomic - condition of
if
should always be a comparison
Explication of control (5.7)
input grammar ast_ir_mon
output grammar ast_ir_mon_exp
type ExprAtom = EConst | EVar
type Expr = ExprAtom | EOp1 | EOp2 | EInput | ECompare
type Stmt = SPrint | SAssign | SCond | SGoto
type Block = IList[Stmt]
type Program = dict[Label, Block]
class SCond:
test: ECompare
body: Label
orelse: Label
class SGoto:
target: Label
- statement lists in conditional replaced by jump labels (here:
Label
) - New goto statement
Write two functions
def explicate(p: src.Program) -> tuple[tgt.Program, Label, Label]:
def explicate_block(out: tgt.Program, Lentry: Label, Lexit: Label, p: src.Program):
explicate
creates a program dictionary and entry and exit labelsexplicate_block
- traverses a block for a conditional
- introduces labels for the true branch, the false branch and the continuation (the code following the conditional)
- recursively invokes
explicate_block
to translate the true branch and the false branch - emits the new
SCond
and inserts the properSGoto
s SCond
finishes a block, so we have to start a new block using the continuation label
Roughly:
SCond( test, body, orelse )
... more code ...
-->
SCond( test, Ltrue, Lfalse )
Ltrue:
code for body
SGoto Lcont
Lfalse:
code for orelse
SGoto LCont
Lcont:
explicate ... more code ...
Instruction Selection (5.8)
- raise from single block to dict of blocks
- all conditional statements with comparison have the shape like this
if a1 == a2: goto ltrue; else goto lfalse
with atomsa1
anda2
so we can generate a conditional branch instruction - for reifying the result of a comparison in, say, a boolean variable
check the instructions
slt
andsltu
Register Allocation (5.9)
- need to update liveness analysis
- works on control flow graph
Control Flow Graph (CFG)
A directed graph with
-
nodes = basic blocks, i.e., a sequence of instructions starting with a label and ending with a (conditional) jump.
-
edges = from block ending with a jump to
L
to block starting with labelL
-
Each block has either one or two outgoing edges.
-
Each block has one or more incoming edges.
-
One node is labeled
entry
, the labelexit
points to the conclusion of the code.
Liveness Analysis
-
currently, the CFG is a DAG
-
for each node labeled
L
in the CFG, we maintain sets of variableslive_after(L)
andlive_before(L)
-
initially all sets are empty
-
process all nodes in reverse topological order, i.e., the nodes pointing to
exit
first -
liveness analysis for node
L
:- set
live_after(L)
tolive_before(L1)
U … Ulive_before(Ln)
whereL1
…Ln
are the immediate successors ofL
in the CFG - calculate
live_before(L)
by transforminglive_after(L)
according to the gen/kill rules of liveness analysis
- set
-
may calculate the interference right away without storing
live_after
for each individual instruction
Optimize Blocks / Remove Jumps
- the material of 5.12.1 is not obviously applicable to our approach
- but the same effect can be achieved using the approach of 5.12.2 or by partially evaluating conditionals earlier in the pipeline
While
control flow graph for summation from 0-5
mainstart
|
block5
/ ^ \
| | |
block7 block8
|
exit
- it’s cyclic
- no traversal in topological order possible
- set up liveness information as before
- compute
live_before
fromlive_after
until nolive_before
changes. - called fixed point iteration
For instance, suppose sum
is live in block8
.
-> sum in live_after(block5)
-> sum in live_before(block5)
-> live_after(block7) = live_before(block5)
which contains sum
-> sum
in live_before(block7)
- it’s also correct to compute the interference graph during the fixed point iteration
Suppose LA(ins)
is some life after set.
Consider instruction ins
and LB(ins)
the corresponding life before
set.
If LA(ins)
gets bigger, then LB(ins)
stays the same or gets
bigger.
Because LB(ins) = (LA(ins) \ W(ins)) U R(ins)
where W(ins)
and R(ins)
are constant sets (because the instruction
ins
is fixed).
So technically, this computes a monotone function.