3.
Stack Storage Allocation with Example
Each function call creates an activation record on the stack.
Example:
int factorial(int n) {
if(n <= 1) return 1;
return n * factorial(n - 1);
Each recursive call pushes a new activation record. The stack grows with deeper recursion and
shrinks as calls return.
4. Heap Memory Management
Heap allows dynamic allocation at runtime (e.g., malloc in C).
- Memory is not automatically freed.
- Requires manual deallocation (free) or garbage collection.
5. Accessing Non-local Data Using Access Links and Displays
Access Links:
- Each activation record contains a link to its static ancestor.
- Used in nested functions to access variables in enclosing scopes.
Displays:
- An array of pointers to activation records at each nesting level.
- Faster than access links for deep nesting.
6. Garbage Collection
a) Reference Counting:
- Each object has a counter of references.
- Incremented/decremented as references are assigned/removed.
- Freed when count is zero.
Drawback: Can't handle cyclic references.
b) Mark-and-Sweep:
- Mark phase: Traverse from roots and mark reachable objects.
- Sweep phase: Free all unmarked objects.
- Handles cycles, but slower.
7. Issues in the Design of a Code Generator
- Target architecture constraints (registers, instruction set)
- Instruction selection: Which instructions to use
- Instruction ordering: To reduce stalls, pipeline hazards
- Register allocation: Efficient register usage
- Evaluation order of sub-expressions
- Calling conventions
8. Peephole Optimization Techniques
- Constant Folding: 3 + 5 8
- Strength Reduction: x * 2 x + x
- Algebraic Simplifications: x * 1 x, x + 0 x
- Redundant Load/Store elimination
- Unreachable Code Removal
Example:
MOV R1, R2
MOV R2, R1 eliminated
9. Code Generation Algorithm
Input: Intermediate code (e.g., 3-address code)
Output: Target assembly
Algorithm:
- For each instruction:
- Determine operands (register/memory)
- Select target instruction
- Allocate registers
- Emit code
Example:
a=b+c
LOAD R1, b
ADD R1, c
STORE R1, a
10. Constructing Flow Graph
- Nodes: Basic blocks
- Edges: Flow of control (jumps, branches)
Example:
if (x > 0)
x = x - 1;
else
x = x + 1;
Flow graph:
[block1] [block2]
[block3]
11. Partitioning TAC into Basic Blocks
Algorithm:
1. Identify leaders:
- First instruction
- Targets of jumps
- Instruction after jump
2. For each leader, create a block ending at next leader or end
Example:
1: a = b + c
2: if a > 0 goto L1
3: d = a - 1
4: goto L2
5: L1: d = a + 1
6: L2: e = d * 2
Leaders: 1, 5, 6
Basic Blocks:
B1: 12
B2: 34
B3: 5
B4: 6
12. Register Allocation Strategies
- Graph Coloring:
- Build interference graph
- Assign registers such that no adjacent nodes share register
- Linear Scan:
- Traverse intervals linearly
- Allocate registers to live variables
- Register Spilling:
- Store some variables in memory when registers are full
Goal: Minimize memory access and use registers efficiently.