Intermediate Code Generation — Full
Explanation
1. Definition
Intermediate Code Generation is a stage in the compiler design process where the compiler
converts the high-level source code (like C, Java) into a middle-level code, which is
between high-level language and machine code.
This code is called Intermediate Representation (IR).
It is independent of any machine or hardware, so it can be easily converted to machine
code later.
2. Concept (Meaning in Simple Language)
The idea behind Intermediate Code Generation is:
High-level languages are easy for humans but difficult for machines.
Machine code is easy for computers but hard for humans.
So, the compiler uses a middle step called intermediate code.
This intermediate code is:
Simple like assembly
Independent of CPU architecture
Easy to optimize
Easy to translate into final machine code
Common forms of IR are:
Three-Address Code (TAC)
Example:
t1 = a + b
t2 = t1 * c
Syntax Trees
Postfix notation
Quadruples, Triples, Indirect Triples
Intermediate code acts as a bridge between the frontend (parsing, semantic analysis) and the
backend (optimization and code generation).
3. Functions of Intermediate Code Generation
The main functions are:
1. Breaks program into simple steps
Complex statements are broken into simple instructions.
2. Makes code independent of hardware
Same IR can be used for many machines.
3. Helps in optimization
Makes it easy to apply optimization techniques (constant folding, dead code elimination).
4. Simplifies final code generation
The backend just translates IR into the processor’s machine code.
5. Detects errors earlier
Semantic errors become easier to catch during IR creation.
6. Provides uniform representation
Works as a common model for different compilers.
4. Advantages
1. Machine Independence
IR is not tied to any hardware; the same IR can work for different machines.
2. Easier Optimization
Optimizing IR is easier than optimizing machine code.
3. Simpler Code Generation
Final machine code generation becomes smooth and structured.
4. Better Error Detection
Semantic and type errors are detected while generating IR.
5. Supports Retargeting
Compiler can support multiple architectures by
changing only the backend.
6. Handles complex constructs easily
Loops, conditions, arrays, and functions become easier to process.
5. Disadvantages
1. Extra Stage Increases Compilation Time
Adding IR generation makes compilation longer.
2. Needs More Space
IR may require memory to store temporary variables like t1, t2, etc.
3. More Complexity in Compiler Design
The compiler becomes more complex since it has one more phase.
4. Requires Good Design of IR
A poorly designed IR will produce poor final machine code.
Types of Intermediate Code
In compiler design, intermediate code is generated between the high-level code and machine
code.
The commonly used types of intermediate representations (IR) are:
1. Postfix Notation (Reverse Polish Notation
– RPN)
Definition:
Postfix notation is a form where the operator comes after the operands.
It removes the need for parentheses.
Example:
Infix: a + b * c
Postfix: a b c * +
Features:
Simple to evaluate using a stack
No operator precedence rules needed
No parentheses required
Advantages:
Easy for computers to evaluate
Compact representation
Disadvantages:
Harder for humans to read
Not suitable for complex optimizations
2. Syntax Tree (Abstract Syntax Tree –
AST)
Definition:
A Syntax Tree is a tree representation of the program where:
Internal nodes = operators
Leaf nodes = operands
Example:
Expression: a + b * c
+
/ \
a *
/ \
b c
Features:
Shows the hierarchical structure
Easy to check semantics
Easy for optimization
Advantages:
Removes parentheses automatically
Shows structure clearly
Helps detect errors
Disadvantages:
Takes more memory
More complex to build
3. Three-Address Code (TAC)
Definition:
TAC is an intermediate form where each instruction has at most 3 addresses
(1 result + 2 operands).
Example:
For a + b * c:
t1 = b * c
t2 = a + t1
Features:
Looks like simple assembly
Uses temporary variables (t1, t2)
Machine-independent
Advantages:
Easy to optimize
Easy to convert to machine code
Most commonly used IR
Disadvantages:
Needs extra temporary variables
More instructions than postfix
Final Short Summary (for last-minute
revision)
Type Meaning Example Why Used?
Postfix Notation Operators after operands a b c * + Easy evaluation
Tree of operators and Tree
Syntax Tree (AST) Structure + semantic checks
operands format
Three-Address Code Most used IR, good for
At most 3 operands t1 = b*c
(TAC) optimization
INTERMEDIATE CODE
OPTIMIZATION
(Definition, Need, Types, Functions, Examples, Advantages, Disadvantages)
1. Definition
Intermediate Code Optimization is the process of improving the intermediate code (IC)
generated by the compiler so that the final machine code becomes faster, smaller, and more
efficient without changing the meaning of the program.
✔ It is done on Intermediate Representation (IR)
✔ IR may be Three-address code (TAC), Syntax tree, Postfix, etc.
✔ Optimization improves performance and reduces resource usage.
2. Why Optimization is Needed?
We do optimization to:
Increase speed of the program (less execution time)
Reduce memory usage (fewer variables, fewer instructions)
Improve CPU efficiency
Produce better-quality machine code
Make the program run faster on all hardware types
3. Goals of Optimization
Do not change the meaning of the program
Improve efficiency
Reduce redundant work
Reduce number of instructions
Improve use of registers
Remove useless/unused code
⭐ Role of Code Optimizer (in simple
language)
A code optimizer is a part of the compiler that improves the intermediate code so that the
final machine code becomes:
✔ faster
✔ smaller
✔ uses less memory
✔ efficient for CPU and cache
It does NOT change the meaning of the program, only improves its performance.
⭐ Main Role / Purpose of Code Optimizer
1. Improve Execution Speed
Optimizer removes slow or unnecessary operations so the program runs faster.
Example:
x = x + 0 → removed
x = x * 1 → removed
2. Reduce Memory Usage
It reduces memory by removing useless variables and reusing registers.
3. Reduce Code Size
Smaller machine code takes less space and loads faster.
Example:
Replacing long operations with short ones.
4. Remove Redundant (Useless) Computations
Example:
t1 = a + b
t2 = a + b → second one removed
5. Improve Register Allocation
Keeps important variables in registers to reduce memory access time.
6. Improve Cache Performance
Loop optimization helps data stay in cache, which increases speed.
Example: Loop interchange, loop fusion, loop unrolling.
7. Better Instruction Scheduling
Rearranges instructions to avoid pipeline stall in CPU.
8. Prepare Code for Final Machine Code Generation
Makes the intermediate code suitable and optimized for the target machine.
⭐ Functions of Code Optimizer
1. Local Optimization
Within a basic block
(example: constant folding, copy propagation)
2. Global Optimization
Across the whole program
(example: dead code elimination, loop optimization)
3. Machine-independent optimization
Does not depend on machine architecture.
(example: removing redundancy)
4. Machine-dependent optimization
Depends on CPU design.
(example: instruction scheduling, register allocation)
⭐ Advantages of Code Optimization
✔ Faster program execution
✔ Reduces memory and code size
✔ Improves CPU and cache efficiency
✔ Better performance on limited hardware
✔ Saves power (important for mobiles/embedded systems)
⭐ Disadvantages of Code Optimization
✘ Increases compiler complexity
✘ Takes extra time to compile
✘ Sometimes makes debugging difficult
✘ Hard to design for different architectures