Code Generation for
Control Flow
Mooly Sagiv
html://www.math.tau.ac.il/~msagiv/courses/wcc03.html
Chapter 6.4
Outline
• Local flow of control
– Conditionals
– Switch
– Loops
• Routine Invocation
• Non-local gotos
• Runtime errors
• Handling Exceptions
• Summary
Machine Code Assumptions
Instruction Meaning
GOTO Label Jump to
Label
GOTO label register Indirect
jump
IF condition register then GOTO Label Conditional
Jump
IF not condition register then GOTO Label
Boolean Expressions
• In principle behave like arithmetic
expressions
• But are treated specially
– Different machine instructions
– Shortcut computations
Code for a 5))
Example
x = ((7 * a) + b) if
&& :=
== > x +
a 0 b 5
* b
7 a
if
Lt Lf
&& Lt: := Lf:
No label Lf x +
Lt Lf
== >
* b
Cmp_Constant R0, 0 Cmp_Constant R0, 5
IF NOT EQ THEN GOTO Lf IF GT THEN GOTO Lt 7 a
GOTO Lf
Code for :=
a 0 b 5
Load_Local -8(FP), R0 Load_Local -12(FP), R0
Location Computation for Booleans
Code generation for IF
Allocate two new labels Lf, Lend
Lend:
Generate code for Boolean(left, 0, Lf)
if GOTO Lend
Lf:
Boolean expression true sequence false sequence
Code for Code for
Code for Boolean with jumps
to Lf true sequence false sequence
Code generation for IF (no-else)
Allocate new label Lend
Lend:
Generate code for Boolean(left, 0, Lend)
if
Boolean expression true sequence
Code for
Code for Boolean with jumps
to Lend true sequence
Coercions into value computations
:= Generate new label Lf
Load_Constant R0, 0;
Generate code for Boolean(right, 0, Lf)
x a>b
Load_Local -8(FP), R1;
CMP R1, -12(FP) ;
IF Lhigh GOTO label_else;
GOTO table[tmp_case_value –Llow];
Balanced trees
• The jump table may be inefficient
– Space consumption
– Cache performance
• Organize the case labels in a balanced tree
– Left subtrees smaller labels
– Right subtrees larger labels
• Code generated for node_k
label_k: IF tmp_case_value lk THEN
GOTO label of right branch;
code for statement sequence;
GOTO label_next;
Repetition Statements (loops)
• Similar to IFs
• Preserve language semantics
• Performance can be affected by different
instruction orderings
• Some work can be shifted to compile-time
– Loop invariant
– Strength reduction
– Loop unrolling
while statements
Generate new labels test_label, Lend
test_label: while Generate code for Boolean(left, 0, L )
end
GOTO test_label;
Lend:
statement
Boolean
Sequence
expression
Code for
Code for Boolean with statement sequence
jumps to Lend
while statements(2)
Generate labels test_label, Ls
GOTO test_label: while Generate code for Boolean(left, Ls, 0)
Ls:
Code for
test_label:
statement sequence statement
Boolean
Sequence
expression
Code for Boolean with
jumps to LS
For-Statements
• Special case of while
• Tricky semantics
– Number of executions
– Effect on induction variables
– Overflow
Simple-minded translation
FOR i in lower bound .. upper bound DO
statement sequence
END for
i := lower_bound;
tmp_ub := upper_bound;
WHILE I tmp_ub THEN GOTO end_label;
loop_label:
code for statement sequence
if (i==tmp_ub) GOTO end_label;
i := i + 1;
GOTO loop_label;
end_label:
Tricky question
Loop unrolling
FOR i := 1 to n DO
sum := sum + a[i];
END FOR;
Summary
• Handling control flow statements is usually
simple
• Complicated aspects
– Routine invocation
– Non local gotos
– Runtime errors
• Runtime profiling can help
Routine Invocation
• Identify the called routine
• Generate calling sequence
– Some instructions are executed by the callee
• Filling the activation record
– Actual parameters (caller)
– Administrative part
– The local variable area
– The working stack
Parameter Passing Mechanisms
• By value • Pass the R-value of the parameter
• By reference • Pass the L-value of the parameter
• By result • Pass the L-value of the parameter
• By value-result • The callee creates a temporary
• Stores the temporary upon return
• Can use registers
• Pass the L-value of the parameter
• The callee creates a temporary
• Store the temporary upon return
Caller Sequence
• Save caller-save registers
• Pass actual parameters
– In stack
– In register
• Pass lexical pointer
• Generate code for the call
– Store return address
– Pass flow of control
Callee Sequence
• Allocate the frame
• Store callee-save registers
• Perform the procedure code
• Return function result
• Restore callee-save registers
• Deallocate the frame
• Transfer the control back to the caller
Two activation records on the stack
Non-Local goto in C syntax
Non-local gotos
• Close activation records
• Restore callee-save registers
code Memory before Memory After
Main Main
p:
l:
p p
q: r
goto l; q
Runtime errors
• The smartest compiler cannot catch all
potential errors at compile-time
– Missing information
– Undecidability
• Compiler need to generate code to identify
runtime errors
– Non-trivial
Common runtime errors
• Overflow
– Integers
– Stack frame
• Limited resources
• Division by zero
• Null pointer dereferences
• Dangling pointer dereferences
• Buffer overrun (array out of bound)
Runtime Errors
• C
– No support for runtime errors
– Situations with “undefined” ANSI C semantics
• Leads to security vulnerabilities
• Pascal
– Runtime errors abort execution
• Java
– Runtime errors result in raised exceptions
– Can be handled by the programmer code
Detecting a runtime error
• Array bound-check
foo() { if (“i” =100)
int a[100], i, j;
THROW range_error;
scanf(“%d%d”, &i, &j);
while (i =0) && j <=100) {
while (i < j) {
a[i] = i ;
i++;
}
else …
}
Handling Runtime Errors
• Abort
• Statically assigned error handlers (signal)
• Exceptions
Signal Handlers
• Binds errors to handler routines
• Invoke a specific routine when runtime
error occurs
• Report an error
– Close open resources and exit
– Resume immediately after the error
– Resume in some “synchronization” point
Signal Example
Exceptions
• Flexible mechanism for handling runtime errors
• Available in modern programming languages
• Useful programming paradigm
• But are hard to compile
void f() {
void g() { void h() {
{ … g() …
… h() … … throw error1 …
catch(error1) {
} }
…}
}
}
Why are exceptions hard to compile?
• Dynamic addresses
– Not always known when at compile time
– Non local goto
– Register state
• The handler may change in the execution of
a routine
• The handler code assumes sequential
execution
Handling Exceptions
• At compile time store mappings from
exceptions to handlers
• Store a pointer to the table in the activation
record
• When an exception is raised scan the stack
frames to locate the most recent handler
• Perform a non-goto
Handler Code Block/Routine
• Generate code for • Generate a table
handler exception handler
• Terminate with a jump
to the end of • Store a pointer to the
block/routine table at the activation
• A unique label where record
the handler code
begins
Code for raising exception
• Extract the pointer to the table from the
activation record
• Search for a handler for the exception raised
• If not found pop the stack and repeat
• If found perform a non-local goto
• Usually combine the search and the goto
Summary
• Non local transfer of control can be
expensive
– Hard to understand = Hard to implement
• But are necessary
• Challenging optimization problems