Dana Vrajitoru 
C311 Programming Languages 
Semantics, Attribute Grammars, Target Code Optimization
Semantic Analysis
- Analyzing the meaning of the program/tree/sentence/image/etc.
 - For a program: it is not done with a context free grammar because
it needs to check for consistencies in the program.
 - Examples: function calls and the number of parameters, the type of
a variable and the type of the value assigned to it.
 - Semantic rules can be static or dynamic. The static rules are
enforced by the compilers. The dynamic ones are enforced at runtime.
 
Attribute Grammars
- They generate parse trees with decorations, or annotations added
to the nodes.
 - These attributes can be properties or even actions to be taken.
 - In some cases, the attribute is an additional value associated
with non terminals and terminals.
 - In other cases, for each rule we associate an action to be taken
with the attributes of the symbols. This can be copy rules or semantic
function calls.
 - Other theoretical AG: denotation semantics (machine-independent
code), axiomatic semantic (proofs).
 
Example
Context-free 
E -> E + T     
E -> E - T
E -> T
...
F -> ( E )
 
 | Attribute Grammar 
E1 -> E2 + T
E1.val := sum(E2.val, T.val)
E1 -> E2 - T
E1.val := difference(E2.val, T.val)
E -> T
E.val := T.val
F -> ( E )
F.val = E.val 
 | 
Evaluating Attributes
- Synthesized attributes: those whose whose values are calculated
only when their symbol appears on the left hand side.
 - Inherited attributes: those whose value is computed even when they
are on the right hand side of a rule.
 - Grammars with synthesized only attributes are called
S-attributed. The attributes of the tokens are initialized by the
scanner. The attribute flow is bottom-up in the parse tree.
 
Inherited Attributes
They allow for the values of the attributes to be passed sideways
and down in the tree. They may add symbol table information.
E -> T TT
TT.st := T.val			E.val := TT.val
TT1 -> + T TT2
TT2.st := TT1.st + T.val	TT1.val := TT2.val
TT1 -> - T TT2
TT2.st := TT1.st - T.val	TT1.val := TT.val
TT -> e				TT.val := TT.st
Attribute Grammars in NLP
Code Optimizers
- The output code must not, in any way, change the meaning of the
program.
 - Optimization should increase the speed of the program and if
possible, the program should require less resources.
 - Optimization should itself be fast and should not delay the
overall compiling process.
 - Can be machine-independent or machine dependent (involving
registers, absolute memory references).
 
Code Optimization
- There are several possible levels of target code improvement.
 - Peephole optimizer: scans already generated code for obvious
suboptimal sequences.
 - Local optimization: improvement of basic blocks, maximal groups
that will execute in their entirety (loops, conditionals, etc.) Mostly
tries to eliminate redundancy.
 - Global optimization: looks at functions in their entirety. They
focus on multi-block elimination of redundancy, instruction
scheduling, register allocation.
 - Interprocedural optimization: more difficult.
 
Peephole Optimization
- Elimination of redundant loads and stores.
 - Constant folding: x = 3 * 2 becomes x = 6.
 - Constant propagation:
r1 = 4
r2 = r2 + r1 becomes r2 = r2 + 4
 - Common subexpression elimination.
 - Strength reduction:
r1 = r2 * 2 becomes r1 = r2 + r2 or r1 = r2 << 1 
 
Local Optimization
- Redundant loads and computations can be merged into individual
nodes with multiple parents.
 - Value numbering assigns the same name (a "number") to any two or
more symbolically equivalent computations ("values"), so redundant
instances will be recognizable by their common name.
 - A dictionary is used to keep track of these values.
 
Loop Optimization
- Invariant code: code that computes the same value in each
iteration.
 - Loop invariant code motion: move the invariant computations
outside (before) the loop.
 - Induction variable: a variable incremented or decrement by
a loop invariant. Can be optimized by strength reduction or common
references.
 - Dead Code elimination: find pieces of code that can never
be reached and eliminate them.
 
|  Original
 |  Optimized
 | 
 do
 {
     item = 10;
     value += item; 
 } while(value < 100);  
 | 
 item = 10;
 do
 {
     value += item; 
 } while(value < 100);  
 | 
Loop Invariant
// Original
do
{
    item = 10;
    value += item; 
} while(value < 100);
// Optimized
item = 10;
do
{
    value += item; 
} while(value < 100);
More Loop Invariant
// Original
for i = 1 to N 
    x = x + 1;
    for j = 1 to N 
        a(i,j) = 100*N + 10*i + j+ x;
// Optimized
t1 = 100*N
for i = 1 to N 
    x = x + 1; 
    for j = 1 to N 
        a(i,j) = t1 + 10*i + j + x;
// Super-Optimized
t1 = 100*N;
for i = 1 to N 
    x = x + 1;
    t2 = t1 + 10*i + x;
    for j = 1 to N 
        a(i, j) = t2 + j;
Induction Variable Reduction
// Original
for i = 1 to N 
    a[i] = b[i];
// Optimized
t1 = &a;
t2 = &b;
for i = 1 to N 
    *t1 = *t2;
    t1++;
    t2++;
Induction Variable in Expressions 
(for i=0; i<n; i++)
    ...
    k = i * b;  
    // b is a loop invariant
// Replace with:
k = 0;
(for i=0; i<n; i++)
    ...
    k += b; 
Applying the Induction Variable Method
// Ultra-Optimized
t2 = 100*N + x;
for i = 1 to N 
    t2 += 11;
    for j = 1 to N 
        a(i,j) = t2 + j;
Global Optimization
- Global common instruction elimination and global variable
numbering.
 - Instruction scheduling: build a tree of dependencies and then use
an algorithm to find an optimal linear sequence of these instructions.
 - Loop improvement: loop unrolling (several iterations in one), loop
reordering (for nested loops), parallelization.