Cs308 compiler theory
1 / 95

CS308 Compiler Theory - PowerPoint PPT Presentation

  • Uploaded on

CS308 Compiler Theory. Syntax-Directed Translation. Grammar symbols are associated with attributes to associate information with the programming language constructs that they represent. Values of these attributes are evaluated by the semantic rules associated with the production rules.

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
Download Presentation

PowerPoint Slideshow about ' CS308 Compiler Theory' - abel-casey

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Cs308 compiler theory

CS308 Compiler Theory

CS308 Compiler Theory

Syntax directed translation
Syntax-Directed Translation

  • Grammar symbols are associated with attributes to associate information with the programming language constructs that they represent.

  • Values of these attributes are evaluated by the semantic rules associated with the production rules.

  • Evaluation of these semantic rules:

    • may generate intermediate codes

    • may put information into the symbol table

    • may perform type checking

    • may issue error messages

    • may perform some other activities

    • in fact, they may perform almost any activities.

  • An attribute may hold almost any thing.

    • a string, a number, a memory location, a complex record.

CS308 Compiler Theory

Syntax directed definitions and translation schemes
Syntax-Directed Definitions and Translation Schemes

  • When we associate semantic rules with productions, we use two notations:

    • Syntax-Directed Definitions

    • Translation Schemes

  • Syntax-Directed Definitions:

    • give high-level specifications for translations

    • hide many implementation details such as order of evaluation of semantic actions.

    • We associate a production rule with a set of semantic actions, and we do not say when they will be evaluated.

  • Translation Schemes:

    • indicate the order of evaluation of semantic actions associated with a production rule.

    • In other words, translation schemes give a little bit information about implementation details.

CS308 Compiler Theory

Syntax directed definitions
Syntax-Directed Definitions

  • A syntax-directed definition is a generalization of a context-free grammar in which:

    • Each grammar symbol is associated with a set of attributes.

    • This set of attributes for a grammar symbol is partitioned into two subsets called synthesized and inherited attributes of that grammar symbol.

    • Each production rule is associated with a set of semantic rules.

  • Semantic rules set up dependencies between attributes which can be represented by a dependency graph.

  • This dependency graph determines the evaluation order of these semantic rules.

  • Evaluation of a semantic rule defines the value of an attribute. But a semantic rule may also have some side effects such as printing a value.

CS308 Compiler Theory

Syntax directed definition example
Syntax-Directed Definition -- Example

ProductionSemantic Rules

L → E return print(E.val)

E → E1 + T E.val = E1.val + T.val

E → T E.val = T.val

T → T1 * F T.val = T1.val * F.val

T → F T.val = F.val

F → ( E ) F.val = E.val

F → digit F.val = digit.lexval

  • Symbols E, T, and F are associated with a synthesized attribute val.

  • The token digit has a synthesized attribute lexval (it is assumed that it is evaluated by the lexical analyzer).

CS308 Compiler Theory

Translation schemes
Translation Schemes

  • In a syntax-directed definition, we do not say anything about the evaluation times of the semantic rules (when the semantic rules associated with a production should be evaluated?).

  • A translation scheme is a context-free grammar in which:

    • attributes are associated with the grammar symbols and

    • semantic actions enclosed between braces {} are inserted within the right sides of productions.

  • Ex:A → { ... } X { ... } Y { ... }

    Semantic Actions

CS308 Compiler Theory

A translation scheme example
A Translation Scheme Example

  • A simple translation scheme that converts infix expressions to the corresponding postfix expressions.

    E → T R

    R → + T { print(“+”) } R1

    R → 

    T → id{ print(id.name) }

    a+b+c ab+c+

    infix expression postfix expression

CS308 Compiler Theory

Type checking
Type Checking

  • A compiler has to do semantic checks in addition to syntactic checks.

  • Semantic Checks

    • Static – done during compilation

    • Dynamic – done during run-time

  • Type checking is one of these static checking operations.

    • we may not do all type checking at compile-time.

    • Some systems also use dynamic type checking too.

  • A type system is a collection of rules for assigning type expressions to the parts of a program.

  • A type checker implements a type system.

  • A sound type system eliminates run-time type checking for type errors.

  • A programming language is strongly-typed, if every program its compiler accepts will execute without type errors.

    • In practice, some of type checking operations are done at run-time (so, most of the programming languages are not strongly-typed).

    • Ex: int x[100]; … x[i]  most of the compilers cannot guarantee that i will be between 0 and 99

CS308 Compiler Theory

Intermediate code generation
Intermediate Code Generation

  • Intermediate codes are machine independent codes, but they are close to machine instructions.

  • The given program in a source language is converted to an equivalent program in an intermediate language by the intermediate code generator.

  • Intermediate language can be many different languages, and the designer of the compiler decides this intermediate language.

    • syntax trees can be used as an intermediate language.

    • postfix notation can be used as an intermediate language.

    • three-address code (Quadraples) can be used as an intermediate language

      • we will use quadraples to discuss intermediate code generation

      • quadraples are close to machine instructions, but they are not actual machine instructions.

    • some programming languages have well defined intermediate languages.

      • java – java virtual machine

      • prolog – warren abstract machine

      • In fact, there are byte-code emulators to execute instructions in these intermediate languages.

CS308 Compiler Theory

Three address code quadraples
Three-Address Code (Quadraples)

  • A quadraple is:

    x := y op z

    where x, y and z are names, constants or compiler-generated temporaries; op is any operator.

  • But we may also the following notation for quadraples (much better notation because it looks like a machine code instruction)

    op y,z,x

    apply operator op to y and z, and store the result in x.

  • We use the term “three-address code” because each statement usually contains three addresses (two for operands, one for the result).

CS308 Compiler Theory


  • Elements of arrays can be accessed quickly if the elements are stored in a block of consecutive locations.

    A one-dimensional array A:

    baseA low i width

    baseA is the address of the first location of the array A,

    width is the width of each array element.

    low is the index of the first array element

    location of A[i]  baseA+(i-low)*width

CS308 Compiler Theory

Arrays cont
Arrays (cont.)


can be re-written as i*width + (baseA-low*width)

should be computed at run-time can be computed at compile-time

  • So, the location of A[i] can be computed at the run-time by evaluating the formula i*width+c where c is (baseA-low*width) which is evaluated at compile-time.

  • Intermediate code generator should produce the code to evaluate this formula i*width+c (one multiplication and one addition operation).

CS308 Compiler Theory

Two dimensional arrays cont
Two-Dimensional Arrays (cont.)

  • The location of A[i1,i2] is

    baseA+ ((i1-low1)*n2+i2-low2)*width

    baseA is the location of the array A.

    low1 is the index of the first row

    low2 is the index of the first column

    n2 is the number of elements in each row

    width is the width of each array element

  • Again, this formula can be re-written as

    ((i1*n2)+i2)*width + (baseA-((low1*n1)+low2)*width)

    should be computed at run-timecan be computed at compile-time

CS308 Compiler Theory

Multi dimensional arrays
Multi-Dimensional Arrays

  • In general, the location of A[i1,i2,...,ik] is

    (( ... ((i1*n2)+i2) ...)*nk+ik)*width + (baseA-((...((low1*n1)+low2)...)*nk+lowk)*width)

  • So, the intermediate code generator should produce the codes to evaluate the following formula (to find the location of A[i1,i2,...,ik]) :

    (( ... ((i1*n2)+i2) ...)*nk+ik)*width+ c

  • To evaluate the (( ... ((i1*n2)+i2) ...)*nk+ik portion of this formula, we can use the recurrence equation:

    e1 = i1

    em = em-1 * nm + im

CS308 Compiler Theory

Translation scheme for arrays
Translation Scheme for Arrays

S  L := E { if (L.offset is null) emit(‘mov’ E.place ‘,,’ L.place)

else emit(‘mov’ E.place ‘,,’ L.place ‘[‘ L.offset ‘]’) }

E  E1 + E2 { E.place = newtemp();

emit(‘add’ E1.place ‘,’ E2.place ‘,’ E.place) }

E  ( E1 ) { E.place = E1.place; }

E  L { if (L.offset is null) E.place = L.place)

else { E.place = newtemp();

emit(‘mov’ L.place ‘[‘ L.offset ‘]’ ‘,,’ E.place) } }

CS308 Compiler Theory

Translation of flow of control statements
translation of flow-of-control statements

S  if (E) S1

| if (E) S1 else S2

| while (E) S1

| S1 S2

S.next : the label that is attached to the first three-address code to be executed after the code for S

Code for flow of control statements

to E.true

to E.true



to E.false

to E.false





. . .

goto S.next



(a) if-then

. . .

(b) if-then-else


to E.true


to E.false



goto S.begin

. . .

(c) while-do

code for flow-of-control statements




Fall through
利用fall through

E  E1 relop E2

{test = E1 relop E2

s = if E.true != fall and E.false != fall then

gen(‘if’ test ‘goto’, E.true) || gen(‘goto’, E.false)

else if (E.true != fall) then gen(‘if’ test ‘goto’, E.true)

else if (E.false != fall) then gen(‘if’ ! test ‘goto’, E.false)

else ‘’

E.code := E1.code || E2 .code || s



allows generation of intermediate code in one pass (the problem with translation scheme before is that we have inherited attributes such as S.next, which is not suitable to implement in bottom-up parsers)

idea: the labels (in the three-address code) will be filled when we know the places

  • attributes: E.truelist (true exits:真标号表), E.falselist (false exits)

  • S  if E then M S1

    {backpatch(E.truelist, M.quad);

    S.nextlist := merge(E.falselist, S1.nextlist}

  • S  if E then M1S1 N else M2S2

    {backpatch(E.truelist, M1.quad);

    backpatch(E.falselist, M2.quad);

    S.nextlist := merge(S1.nextlist, N.nextlist, S2.nextlist)}

Run time environments
Run-Time Environments

  • How do we allocate the space for the generated target code and the data object of our source programs?

  • The places of the data objects that can be determined at compile time will be allocated statically.

  • But the places for the some of data objects will be allocated at run-time.

  • The allocation and de-allocation of the data objects is managed by the run-time support package.

    • run-time support package is loaded together with the generate target code.

    • the structure of the run-time support package depends on the semantics of the programming language (especially the semantics of procedures in that language).

  • Each execution of a procedure is called as activation of that procedure.

CS308 Compiler Theory

Procedure activations
Procedure Activations

  • An execution of a procedure starts at the beginning of the procedure body;

  • When the procedure is completed, it returns the control to the point immediately after the place where that procedure is called.

  • Each execution of a procedure is called as its activation.

  • Lifetime of an activation of a procedure is the sequence of the steps between the first and the last steps in the execution of that procedure (including the other procedures called by that procedure).

  • If a and b are procedure activations, then their lifetimes are either non-overlapping or are nested.

  • If a procedure is recursive, a new activation can begin before an earlier activation of the same procedure has ended.

CS308 Compiler Theory

Activation tree cont
Activation Tree (cont.)






CS308 Compiler Theory

Run time storage organization
Run-Time Storage Organization

Memory locations for code are

determined at compile time.

Locations of static data can also be

determined at compile time.

Data objects allocated at run-time.

(Activation Records)

Other dynamically allocated data

objects at run-time. (For example,

malloc area in C).

CS308 Compiler Theory

Activation records
Activation Records

  • Information needed by a single execution of a procedure is managed using a contiguous block of storage called activation record.

  • An activation record is allocated when a procedure is entered, and it is de-allocated when that procedure exited.

  • Size of each field can be determined at compile time (Although actual location of the activation record is determined at run-time).

    • Except that if the procedure has a local variable and its size depends on a parameter, its size is determined at the run time.

CS308 Compiler Theory

Activation records cont
Activation Records (cont.)

The returned value of the called procedure is returned

in this field to the calling procedure. In practice, we may

use a machine register for the return value.

The field for actual parameters is used by the calling

procedure to supply parameters to the called procedure.

The optional control link points to the activation record

of the caller.

The optional access link is used to refer to nonlocal data

held in other activation records.

The field for saved machine status holds information about

the state of the machine before the procedure is called.

The field of local data holds data that local to an execution

of a procedure..

Temporay variables is stored in the field of temporaries.

CS308 Compiler Theory

Access to nonlocal names
Access to Nonlocal Names

  • Scope rules of a language determine the treatment of references to nonlocal names.

  • Scope Rules:

    • Lexical Scope (Static Scope)

      • Determines the declaration that applies to a name by examining the program text alone at compile-time.

      • Most-closely nested rule is used.

      • Pascal, C, ..

    • Dynamic Scope

      • Determines the declaration that applies to a name at run-time.

      • Lisp, APL, ...

CS308 Compiler Theory

Access links
Access Links

program main;

var a:int;

procedure p;

var d:int;

begin a:=1; end;

procedure q(i:int);

var b:int;

procedure s;

var c:int;

begin p; end;


if (i<>0) then q(i-1)

else s;


begin q(1); end;



CS308 Compiler Theory


  • An array of pointers to activation records can be used to access

  • activation records.

  • This array is called as displays.

  • For each level, there will be an array entry.

Current activation record at level 1

Current activation record at level 2

Current activation record at level 3

CS308 Compiler Theory

Accessing nonlocal variables using display
Accessing Nonlocal Variables using Display




addrC := offsetC(D[3])

addrB := offsetB(D[2])

addrA := offsetA(D[1])

ADD addrA,addrB,addrC

program main;

var a:int;

procedure p;

var b:int;

begin q; end;

procedure q();

var c:int;




begin p; end;

CS308 Compiler Theory

Issue in the design of a code generator
Issue in the Design of a Code Generator

  • General tasks in almost all code generators: instruction selection, register allocation and assignment.

    • The details are also dependent on the specifics of the intermediate representation, the target language, and the run-time system.

  • The most important criterion for a code generator is that it produce correct code.

  • Given the premium on correctness, designing a code generator so it can be easily implemented, tested, and maintained is an important design goal.

Instruction selection
Instruction Selection

  • The nature of the instruction set of the target machine has a strong effect on the difficulty of instruction selection. For example,

    • The uniformity and completeness of the instruction set are important factors.

    • Instruction speeds and machine idioms are another important factor.

      • If we do not care about the efficiency of the target program, instruction selection is straightforward.

x = y + z  LD R0, y

ADD R0, R0, z

ST x, R0

a = b + c  LD R0, b

d = a + e ADD R0, R0, c

ST a, R0

LD R0, a

ADD R0, R0,e

ST d, R0


Register allocation
Register Allocation

  • A key problem in code generation is deciding what values to hold in what registers.

  • Efficient utilization is particularly important.

  • The use of registers is often subdivided into two subproblems:

    • Register Allocation, during which we select the set of variables that will reside in registers at each point in the program.

    • Register assignment, during which we pick the specific register that a variable will reside in.

  • Finding an optimal assignment of registers to variables is difficult, even with single-register machine.

  • Mathematically, the problem is NP-complete.

A simple target machine model
A Simple Target Machine Model

  • Our target computer models a three-address machine with load and store operations, computation operations, jump operations, and conditional jumps.

  • The underlying computer is a byte-addressable machine with n general-purpose registers.

  • Assume the following kinds of instructions are available:

    • Load operations

    • Store operations

    • Computation operations

    • Unconditional jumps

    • Conditional jumps

Basic blocks and flow graphs
Basic Blocks and Flow Graphs

  • Introduce a graph representation of intermediate code that is helpful for discussing code generation

    • Partition the intermediate code into basic blocks

    • The basic blocks become the nodes of a flow graph, whose edges indicate which blocks can follow which other blocks.

CS308 Compiler Theory

Optimization of basic blocks
Optimization of Basic Blocks

  • Local optimization within each basic block

  • Global optimization

    • which looks at how information flows among the basic blocks of a

  • This chapter focuses on the local optimization

CS308 Compiler Theory

Dag representation of basic blocks
DAG Representation of Basic Blocks

  • Construct a DAG for a basic block

    1. There is a node in the DAG for each of the initial values of the variables appearing in the basic block.

    2. There is a node Nassociated with each statement s within the block. The children of Nare those nodes corresponding to statements that are the last definitions, prior to s,of the operands used by s.

    3. Node Nis labeled by the operator applied at s, and also attached to N is the list of variables for which it is the last definition within the block.

    4. Certain nodes are designated output nodes. These are the nodes whose variables are live on exit from the block; that is, their values may be used later, in another block of the flow graph.

CS308 Compiler Theory

Finding local common sub expressions
Finding Local Common Sub expressions

  • How about if b and d are live on exit?

CS308 Compiler Theory

Dead code elimination
Dead Code Elimination

  • Delete from a DAG any root (node with no ancestors) that has no live variables attached.

  • Repeated application of this transformation will remove all nodes from the DAG that correspond to dead code.

  • Example: assume a and b are live but c and e are not.

    • e , and then c can be deleted.

CS308 Compiler Theory

The use of algebraic identities
The Use of Algebraic Identities

  • Eliminate computations

  • Reduction in strength

  • Constant folding

    • 2*3.14 = 6.28 evaluated at compile time

  • Other algebraic transformations

    • x*y=y*x

    • x>y and x-y>0

    • a= b+c; e=c+d+b; e=a+d;

  • CS308 Compiler Theory

    Representation of array references
    Representation of Array References

    • x = a[i]

    • a[j]=y

    • killed node

    CS308 Compiler Theory

    Reassembling basic blocks from dag s
    Reassembling Basic Blocks From DAG 's

    b is not live on exit

    b is live on exit

    CS308 Compiler Theory

    Register and address descriptors
    Register and Address Descriptors

    • Descriptors are necessary for variable load and store decision.

    • Register descriptor

      • For each available register

      • Keeping track of the variable names whose current value is in that register

      • Initially, all register descriptors are empty

    • Address descriptor

      • For each program variable

      • Keeping track of the location (s) where the current value of that variable can be found

      • Stored in the symbol-table entry for that variable name.

    CS308 Compiler Theory

    The code generation algorithm
    The Code-Generation Algorithm

    • FunctiongetReg(I)

      • Selecting registers for each memory location associated with the three-address instruction I.

    • Machine Instructions for Operations

      • For a three-address instruction such as x = y + z, do the following:

        1. Use getReg(x = y + z) to select registers for x, y, and z. Call these Rx, Ry, and Rz .

        2 . If y is not in Ry (according to the register descriptor for Ry) , then issue an instruction

        LD Ry , y' , where y' is one of the memory locations for y (according to the address descriptor for y) .

        3. Similarly, if z is not in Rz , issue an instruction LD Rz, z’ , where z’ is a location for z.

        4. Issue the instruction ADD Rx , Ry , Rz.

    CS308 Compiler Theory

    Peephole optimization
    Peephole Optimization

    • The peephole is a small, sliding window on a program.

    • Peephole optimization, is done by examining a sliding window of target instructions and replacing instruction sequences within the peephole by a shorter or faster sequence, whenever possible.

    • Peephole optimization can be applied directly after intermediate code generation to improve the intermediate representation.

    CS308 Compiler Theory

    Eliminating unreachable code
    Eliminating Unreachable Code

    • An unlabeled instruction immediately following an unconditional jump may be removed.

    • This operation can be repeated to eliminate a sequence of instructions.

    CS308 Compiler Theory

    Flow of control optimizations
    Flow-of- Control Optimizations

    • Unnecessary jumps can be eliminated in either the intermediate code or the target code by peephole optimizations.

    Suppose there is only one jump to L1

    CS308 Compiler Theory

    Algebraic simplification and reduction in strength
    Algebraic Simplification and Reduction in Strength

    • Algebraic identities can be used to eliminate three-address statements

      • x = x+0; x=x*1

    • Reduction-in-strength transformations can be applied to replace expensive operations

      • x2 ; power(x, 2); x*x

      • Fixed-point multiplication or division; shift

      • Floating-point division by a constant can be approximated as multiplication by a constant

    CS308 Compiler Theory

    Use of machine idioms
    Use of Machine Idioms

    • The target machine may have hardware instructions to implement certain specific operations efficiently.

    • Using these instructions can reduce execution time significantly.

    • Example:

      • some machines have auto-increment and auto-decrement addressing modes.

      • The use of the modes greatly improves the quality of code when pushing or popping a stack as in parameter passing.

      • These modes can also be used in code for statements like x = x + 1 .

    CS308 Compiler Theory

    Register allocation and assignment
    Register Allocation and Assignment

    • Efficient utilization of registers is vitally important in generating good code.

    • This section presents various strategies for deciding at each point in a program :

      • what values should reside in registers (register allocation) and

      • in which register each value should reside (register assignment) .

    CS308 Compiler Theory

    Usage counts
    Usage Counts

    • Keeping a variable x in a register for the duration of a loop L

      • Save one unit for each use of x

      • save two units if we can avoid a store of x at the end of a block.

    • An approximate formula for the benefit to be realized from allocating a register x within loop L is

    where use(x, B) is the number of times x is used in B prior to any definition of x,live(x, B) is 1 if x is live on exit from B and is assigned a value in B, and live(x, B) is 0 otherwise.

    CS308 Compiler Theory

    Code optimization
    Code optimization

    • Elimination of unnecessary instructions

    • Replacement of one sequence of instructions by a faster sequence of instructions

    • Local optimization

    • Global optimizations

      • based on data flow analyses

    CS308 Compiler Theory

    Causes of redundancy
    Causes of Redundancy

    • Redundant operations are

      • at the source level

      • a side effect of having written the program in a high-level language

    • Each of high-level data-structure accesses expands into a number of low-level arithmetic operations

    • Programmers are not aware of these low-level operations and cannot eliminate the redundancies themselves.

    • By having a compiler eliminate the redundancies

      • The programs are both efficient and easy to maintain.

    CS308 Compiler Theory

    Common subexpressions
    Common Subexpressions

    • Common subexpression

      • Previously computed

      • The values of the variables not changed

    • Local:

    CS308 Compiler Theory

    Common subexpressions1
    Common Subexpressions

    • Global

    CS308 Compiler Theory

    Copy propagation
    Copy Propagation

    • Copy statements or Copies

      • u = v

    CS308 Compiler Theory

    Dead code elimination1
    Dead-Code Elimination

    • Live variable

      • A variable is live at a point in a program if its value can be used subsequently;

      • otherwise, it is dead at that point.

    • Constant folding

      • Deducing at compile time that the value of an expression is a constant and using the constant instead

    CS308 Compiler Theory

    Code motion
    Code Motion

    • An important modification that decreases the amount of code in a loop

    • Loop-invariant computation

      • An expression that yields the same result independent of the number of times a loop is executed

    • Code Motion takes loop-invariant computation before its loop

    while (i <= limit-2)

    t = limit -2

    while (i <= t)

    CS308 Compiler Theory

    Induction variables and reduction in strength
    Induction Variables and Reduction in Strength

    • Induction variable

      • For an induction variable x, there is a positive or negative constant c such that each time xis assigned, its value increases by c

    • Induction variables can be computed with a single increment (addition or subtraction) per loop iteration

    • Strength reduction

      • The transformation of replacing an expensive operation, such as multiplication, by a heaper one, such as addition

    • Induction variables lead to

      • strength reduction

      • eliminate computation

    CS308 Compiler Theory

    Now We have:


    CS308 Compiler Theory

    Data flow analysis
    Data-Flow Analysis

    • Techniques that derive information about the flow of data along program execution paths

    • Examples

      • One way to implement global common sub expression elimination requires us to determine whether two identical expressions evaluate to the same value along any possible execution path of the program.

      • If the result of an assignment is not used along any subsequent execution path, then we can eliminate the assignment as dead code.

    CS308 Compiler Theory

    Reaching definitions
    Reaching Definitions

    • A definition d reaches a point p if there is a path from the point immediately following d to p, such that d is not "killed" along that path.

    • A definition of a variable x is killed if there is any other definition of x anywhere along the path.

    • Conservative

      • if we do not know whether a statement s is assigning a value to x, we must assume that it mayassign to it.

    CS308 Compiler Theory

    Live variable analysis
    Live-Variable Analysis

    • In live-variable analysis we wish to know for variable x and point p whether the value of x at p could be used along some path in the flow graph starting at p. If so, we say x is live at p; otherwise, x is dead at p.

    • Definitions:

      1. defB: the set of variables defined in Bprior to any use of that variable in B

      2. useB: the set of variables whose values may be used in Bprior to any

      definition of the variable.

    CS308 Compiler Theory

    Available expressions
    Available Expressions

    • An expression x + y is available at a point p:

      • if every path, from the entry node to p evaluates x + y, and after the last such evaluation prior to reaching p, there are no subsequent assignments to x or y.

    • A block kills expression x + y :

      • if it assigns (or may assign) x or y and does not subsequently recompute x + y.

    • A block generates expression x + y :

      • if it definitely evaluates x + y and does not subsequently define x or y.

    CS308 Compiler Theory

    Available expressions1
    Available Expressions

    • Let

      IN[B] be the set of expressions that are available before B

      OUT[B] be the same for the point following the end of B

      e_genB be the expressions generated by B

      e_killB be the set of expressions killed in B

    • Then

    • For all basic blocks B other than ENTRY

    CS308 Compiler Theory

    Partial redundancy elimination
    Partial-Redundancy Elimination

    • Minimize the number of expression evaluations

    • Consider all possible execution sequences in a flow graph, and look at the number of times an expression such as x + y is evaluated.

    • By moving around the places where x + y is evaluated and keeping the result in a temporary variable when necessary, we often can reduce the number of evaluations of this expression along many of the execution paths.

    CS308 Compiler Theory

    The sources of redundancy
    The Sources of Redundancy

    CS308 Compiler Theory

    Anticipation of expressions
    Anticipation of Expressions

    • An expression b + c is anticipated at point p if all paths leading from the point p eventually compute the value of the expression b + c from the values of b and c that are available at that point.

    • When we insert expressions, we should ensure that no extra operations are executed. That is, copies of an expression must be placed only at program points where the expression is anticipated.

    CS308 Compiler Theory

    Loops in flow graphs
    Loops in Flow Graphs

    • Loops are important because programs spend most of their time executing them

    • Optimizations that improve the performance of loops can have a significant impact.

    CS308 Compiler Theory


    • Say node d of a flow graph dominates node n, written d dom n, if every path from the entry node of the flow graph to n goes through d.

    • Every node dominates itself.

      Which nodes are

      dominated by

      each node?

    CS308 Compiler Theory

    Finding dominators
    Finding Dominators

    CS308 Compiler Theory

    Edges in a depth first spanning tree
    Edges in a Depth-First Spanning Tree

    • Advancing edges: going from a node m to a proper descendant of m in the tree

    • Retreating edges: going from a node m to an ancestor of m in the tree (possibly to m itself) .

    • Cross edges: edges m  n such that neither m nor n is an ancestor of the other in the DFST

    CS308 Compiler Theory

    Back edges and reducibility
    Back Edges and Reducibility

    • A back edge is an edge a b whose head b dominates its tail a.

    • For any flow graph, every back edge is retreating, but not every retreating edge is a back edge.

    • A flow graph is said to be reducible if all its retreating edges in any depth-first spanning tree are also back edges.

    CS308 Compiler Theory

    Natural loops
    Natural Loops

    • A natural loop is defined by two essential properties.

      1 . It must have a single-entry node, called the header.

      This entry node dominates all nodes in the loop, or it would not be the sole entry to the loop.

      2. There must be a back edge that enters the loop header.

      Otherwise, it is not possible for the flow of control to return to the header directly from the "loop" ; i.e., there really is no loop.

    CS308 Compiler Theory

    代码优化 – 补充

    • 局部优化

    • 循环优化

    (1)i:=m-1 (2)j:=n

    (3)t1:=4*n (4)v:=a[t1]


    (5)i:=i+1 (6)t2:=4*i

    (7)t3:=a[t2] (8)if t3<v goto(5)


    (9)j:=j-1 (10)t4:=4*j

    (11)t5:=a[t4] (12)if t5>v goto(9)


    (13)if i>=j goto(23)


    (23)t11:=4*i (24)x:=a[t11]

    (25)t12:=4*i (26)t13:=4*n

    (27)t14:=a[t13] (28)a[t12]:=t14

    (29)t15:=4*n (30)a[t15]:=x

    (14)t6:=4*i (15)x:=a[t6]

    (16)t7:=4*i (17)t8:=4*j

    (18)t9:=a[t8] (19)a[t7]:=t9

    (20)t10:=4*j (21)a[t10]:=x

    (22)goto (5)





    1. 合并已知量

    2. 删除公共子表达式

    3. 删除无用赋值

    4. 删除死代码

    1. 合并已知量


    A := OP B 或 A := B OP C


    A := T

    2. 删除公共子表达式


    A := B + C*D

    U := V – C*D如果两个语句之间C和D的值未改变,则第二个语句可使用第一个语句的计算结果T:

    A := B + C*D

    U := V – T

    3. 删除无用赋值


    A := B + C


    A := M + N



    A := M + N

    4. 删除死代码


    if B then S1 else S2



    (1) F:=1 (2) C:=F+E (3) D:=F+3

    (4) B:=A*A (5) G:=B-D (6) H:=E

    (7) I:=H*G (8) J:=D/4 (9) K:=J+C

    (10) L:=H (11) L:=I-J

    第一步:合并已知量,由(1) F:=1,可得:

    (1) F:=1 (2) C:=1+E (3) D:=4

    (4) B:=A*A (5) G:=B-4 (6) H:=E

    (7) I:=H*G (8) J:=1 (9) K:=2+E

    (10) L:=H (11) L:=I-1


    (1) F:=1 (2) C:=1+E (3) D:=4

    (4) B:=A*A (5) G:=B-4 (6) H:=E

    (7) I:=E*G (8) J:=1 (9) K:=2+E

    (10) L:=H (11) L:=I-1

    第三步:删除无用赋值 (10);

    其它可能的无用赋值 (1)、(2)、(3)、(6)、(8)。

    (4) B:=A*A (5) G:=B-4 (7) I:=E*G

    (9) K:=2+E (11) L:=I-1

    循环/全局 优化


    1. 代码外提

    2. 强度削弱

    3. 删除归纳变量

    1. 代码外提

    对x:=op y或x:=y op z,如果y、z均为循环不变量(常数或定值点在L之外),则该运算为循环不变运算,优化时将该运算提到循环入口结点之前所增设的结点中去。

    2. 强度削弱

    基本归纳变量:i := i  c (c为常数)

    同族归纳变量:j := c1*i  c2 (c1、c2为常数)


    j := j + c1*c (c1*c为常数)

    3. 删除归纳变量


    例如:j = 10 * i + 5,判断条件为 i > 10 ,则

    将 i > 10 改为 j > 105,同时删除i相关的语句。





    (2)if i>10 goto (16)

    (3)t1:=2*j (4)t2:=10*i

    (5)t3:=t2+t1 (6)t4:=a0-11

    (7)t5:=2*j (8)t6:=10*i

    (9)t7:=t6+t5 (10)t8:=a0-11 (11)t9:=t8[t7] (12)t10:=t9+1

    (13)t4[t3]:=t10 (14)i:=i+1

    (15)goto (2)



    (16) …...



    1. 代码外提






    (2)if i>10 goto (16)

    (3)t1:=2*j (4)t2:=10*i

    (5)t3:=t2+t1 (6)t4:=a0-11

    (7)t5:=2*j (8)t6:=10*i

    (9)t7:=t6+t5 (10)t8:=a0-11 (11)t9:=t8[t7] (12)t10:=t9+1

    (13)t4[t3]:=t10 (14)i:=i+1

    (15)goto (2)



    (16) …...



    2. 强度削弱









    (2)if i>10 goto (16)



    (11)t9:=t8[t7] (12)t10:=t9+1

    (13)t4[t3]:=t10 (14)i:=i+1

    (15)goto (2)



    (16) …...






    (3)t1:=2*j (6)t4:=a0-11

    (7)t5:=2*j (10)t8:=a0-11





    (2)if i>10 goto (16)




    (11)t9:=t8[t7] (12)t10:=t9+1

    (13)t4[t3]:=t10 (14)i:=i+1

    (15)goto (2)


    (16) …...




    (3)t1:=2*j (6)t4:=a0-11

    (7)t5:=2*j (10)t8:=a0-11

    (4)t2:=10*i (8)t6:=10*i

    (5)t3:=t2+t1 (9)t7:=t6+t5




    (2’’)if t3>s goto (16)


    (4’)t2:=t2+10 (5’)t3:=t3+10

    (8’)t6:=t6+10 (9’)t7:=t7+10

    (11)t9:=t8[t7] (12)t10:=t9+1

    (13)t4[t3]:=t10 (15)goto (2’’)


    (16) …...



    5. 其它优化后

    (3)t1:=2*j (6)t4:=a0-11

    (7)t5:=2*j (10)t8:=a0-11

    (4)t2:=10*i (8)t6:=10*i

    (5)t3:=t2+t1 (9)t7:=t6+t5




    (2’’)if t3>s goto (16)


    (5’)t3:=t3+10 (9’)t7:=t7+10

    (11)t9:=t8[t7] (12)t10:=t9+1

    (13)t4[t3]:=t10 (15)goto (2’’)


    (16) …...