COMPILER CONSTRUCTION ASSIGNMENT
OPTIMIZATION
GROUP MEMBERS
Rose Ongili - C026-01-0951/22
Festus Gitahi - C026-01-0913/2022
Anerico Kakai - C026-01-0969/2022
Faith Irungu - C026-01-0736/2020
Leo Chege- C026-01-0912/2022
Evans Mwaura - C026-01-0911/2022
th
DUE - 25 NOVEMBER, 2024
1. Synthesis
The Techniques used are Loop -Invariant Code Motion and Register Allocation.
Loop Invariant is ideal for moving calculations that do not change within a loop outside the
loop, reducing redundant computations during execution
Register Allocation Techniques optimises the use of CPU registers instead of relying on
slower memory access.
Implementation with Pseudo-code (Before and After
Optimization)
Before Optimization:
function findPath(grid, start, end) {
let path = [];
let size = grid.length;
for (let i = 0; i < size; i++) {
for (let j = 0; j < size; j++) {
let distance = Math.sqrt(Math.pow(start.x - i, 2) +
Math.pow(start.y - j, 2)); // Repeated calculation
if (grid[i][j] === 1 && distance < 10) {
path.push({ x: i, y: j });
}
}
}
return path;
}
After Optimization:
The constants calculations are placed outside the loop to avoid repetition
function findPath(grid, start, end) {
let path = [];
let size = grid.length;
// Loop-Invariant Code Motion: Move constant calculation outside
the loop
const startXSquare = Math.pow(start.x, 2);
const startYSquare = Math.pow(start.y, 2);
for (let i = 0; i < size; i++) {
const iSquare = Math.pow(i, 2); // Reuse iSquare for inner
loop
for (let j = 0; j < size; j++) {
const distance = Math.sqrt(iSquare + Math.pow(j, 2) - 2
* (start.x * i + start.y * j) + startXSquare + startYSquare);
if (grid[i][j] === 1 && distance < 10) {
path.push({ x: i, y: j });
}
}
}
return path;
}
2. Evaluation
Trade-offs of Chosen Techniques:
1. Loop-Invariant Code Motion (LICM):
○ Execution Speed: Significantly improved by reducing redundant
computations within the loop.
○ Memory Usage: Slight increase due to storing intermediate values outside
the loop.
○ Code Maintainability: Reduced maintainability as the code becomes slightly
less intuitive with calculations outside the loop.
2. Register Allocation:
○ Execution Speed: Improved since accessing registers is faster than memory.
○ Memory Usage: Reduced, as registers are faster and smaller than main
memory.
○ Code Maintainability: No direct impact, as the compiler usually handles
register allocation automatically.
DOCUMENTATION
Synthesis (Create)
Step-by-Step Plan for Optimization
Optimization Techniques Chosen:
1. Loop-Invariant Code Motion (LICM):
Repetitive calculations within loops are a common inefficiency in pathfinding algorithms like
Dijkstra's or A*. By moving invariant computations outside the loop, we reduce redundant
operations and significantly enhance execution speed.
Relevance: Pathfinding algorithms often involve nested loops where heuristics or weights
are recalculated unnecessarily.
2. Register Allocation:
Minimising memory accesses is critical in embedded systems. Assigning frequently used
variables to registers ensures faster execution, particularly for variables repeatedly accessed
within tight loops.
Relevance: Embedded systems often have limited memory bandwidth, making
register optimization vital for maintaining real-time performance.
Plan Details:
1. Analyze Code:
- Identify nested loops and their operations.
- Locate calculations within loops that depend on constants or values unchanged across
iterations.
- Identify frequently accessed variables for register allocation.
2. Apply Loop-Invariant Code Motion:
- Extract invariant expressions from loops after ensuring no dependencies are broken.
- Precompute these values outside the loops.
3. Optimise Register Usage:
- Use a register allocation algorithm (e.g., graph colouring) to map frequently used
variables to available registers.
- Minimise spilling to memory by prioritising variables accessed within inner loops.
4. Validate Optimizations:
- Use automated and manual testing to verify correctness.
- Benchmark execution time and memory usage before and after applying optimizations.
Recommendation
Suitability for Real-Time Systems
i. These optimizations are highly suitable for real-time embedded systems, as they
address execution speed—a critical constraint.
ii. LICM ensures repetitive calculations are minimised, directly impacting loop-heavy
algorithms like pathfinding.
iii. Register Allocation improves memory efficiency and speed, making it indispensable for
embedded systems with constrained resources.
Potential Risks:
i. Increased memory usage for storing precomputed data (LICM) should be carefully
managed.
ii. Register allocation is limited by the number of registers in the system, which may
necessitate spilling.
Recommendation:
These optimizations are both feasible and effective for the given scenario. The trade-offs are
manageable within embedded system constraints. The company should proceed with
implementing these optimizations and rigorously test the system under real-world conditions.