Simple Answers & Key Points · 22 Questions
Instruction-Level Parallelism (ILP) refers to the potential for simultaneous execution of multiple instructions within a single processor. It measures how many operations in a program's instruction stream are truly independent and can, in theory, be executed at the same time.
Key Concepts:
Why ILP Matters:
Increasing clock frequency has hit a power wall (~2005). ILP is one of the key architectural approaches to improve performance without increasing frequency — by doing more useful work per clock cycle. This is quantified as IPC (Instructions Per Cycle). A superscalar processor achieving IPC > 1 is exploiting ILP.
Static and Dynamic ILP refer to who is responsible for discovering and scheduling independent instructions — the compiler (software) or the processor hardware.
| Feature | Static ILP (Compiler-Based) | Dynamic ILP (Hardware-Based) |
|---|---|---|
| Responsible Party | The compiler (software). | The processor (hardware). |
| Scheduling Time | Compile-time (static). | Run-time (dynamic). |
| Mechanism | Compiler reorders instructions, unrolls loops, and schedules VLIW execution. | Hardware uses Reservation Stations, Reorder Buffers, and Register Renaming to run instructions out-of-order. |
| Adaptability | Cannot adapt to dynamic runtime events (like cache misses or data-dependent branches). | Highly adaptable; dynamically schedules instructions around cache misses and runtime branches. |
| Binary Compatibility | Poor. Binaries are tied to the specific processor generation; require recompilation for newer CPUs. | Excellent. Legacy binaries run on newer processors without recompilation. |
| Hardware Overhead | Minimal. Simple control logic, highly power-efficient. | High. Complex control logic, power-hungry, and consumes significant chip area. |
| Examples | VLIW processors (e.g., Intel Itanium, TI C6000 DSPs). | Superscalar processors (e.g., Intel Core, AMD Ryzen, Apple Silicon). |
These are the three types of data dependencies between instructions. They define the limits of ILP because dependent instructions cannot execute simultaneously.
1. RAW — Read After Write (True Dependency):
I: ADD R1, R2, R3 (writes to R1)J: SUB R4, R1, R5 (reads R1)2. WAR — Write After Read (Anti-Dependency):
I: SUB R4, R1, R5 (reads R1)J: ADD R1, R2, R3 (writes to R1)3. WAW — Write After Write (Output Dependency):
I: ADD R1, R2, R3 (writes to R1)J: MUL R1, R4, R5 (also writes to R1)The compiler plays a critical role in exposing and organizing ILP for the hardware to exploit. Even in superscalar processors with dynamic scheduling, compiler optimizations significantly boost performance.
Key Compiler Techniques:
LOAD instruction before a dependent ADD to hide the memory access latency.Significance: Without compiler optimization, even the most advanced superscalar hardware would find far fewer independent instructions to execute in parallel. The compiler's global view of the program enables optimizations that localized hardware logic cannot achieve.
Despite decades of architectural innovation, extracting more ILP from programs faces several fundamental limits:
Loop unrolling is a compiler optimization technique that replicates the body of a loop multiple times within a single iteration and adjusts the loop control accordingly. Its primary purpose is to expose more ILP and reduce loop overhead.
Before Unrolling (Original Loop):
for (i = 0; i < 100; i++) {
A[i] = A[i] + B[i];
}
Each iteration has: 1 load A[i], 1 load B[i], 1 add, 1 store A[i], 1 branch (loop test). That's 5 instructions, with the branch consuming 20% of the work.
After Unrolling by Factor 4:
for (i = 0; i < 100; i += 4) {
A[i] = A[i] + B[i];
A[i+1] = A[i+1] + B[i+1];
A[i+2] = A[i+2] + B[i+2];
A[i+3] = A[i+3] + B[i+3];
}
Now each iteration has: 4 loads A, 4 loads B, 4 adds, 4 stores, 1 branch = 17 instructions. The branch now consumes only ~6% of the work.
Benefits:
Drawback: Increased code size (instruction cache pressure). If unrolled too aggressively, the larger loop body may not fit in the I-Cache, causing instruction cache misses.
A Superscalar processor is a CPU that can issue and execute more than one instruction per clock cycle by having multiple parallel execution pipelines (functional units).
Architecture:
How ILP is Achieved (Step-by-Step):
Example: A 4-wide superscalar processor with ideal conditions can retire up to 4 instructions per cycle, achieving an IPC (Instructions Per Cycle) of up to 4.
Out-of-Order (OoO) Execution is a hardware technique where the processor executes instructions in an order determined by the availability of their input data, rather than strictly following the original program order.
Why OoO is Needed:
Consider instructions: I1 (slow cache miss), I2 (depends on I1), I3 (independent of I1 and I2). In an in-order processor, I3 is blocked behind I2, which is blocked behind I1. In an OoO processor, I3 can execute immediately while I1 is still waiting for memory.
How OoO Works:
Relation to ILP: OoO execution is the primary hardware mechanism for exploiting dynamic ILP. By looking ahead through the instruction window and executing independent instructions whenever possible, OoO processors extract significantly more ILP than in-order processors. Modern OoO cores can look at windows of 200-300 instructions to find parallelism.
Tomasulo's Algorithm (developed by Robert Tomasulo at IBM in 1967) is a pioneering hardware scheme for dynamic instruction scheduling that enables out-of-order execution. It was first implemented in the IBM System/360 Model 91 floating-point unit.
Key Hardware Components:
Algorithm Steps:
How It Achieves ILP:
Register Renaming is a hardware technique that maps the limited set of architectural registers (the registers defined by the ISA, e.g., R0-R31) to a much larger pool of hidden physical registers. This eliminates WAR and WAW false dependencies.
The Problem (False Dependencies):
I1: ADD R1, R2, R3 (Writes R1)
I2: SUB R4, R1, R5 (Reads R1 — True RAW dependency on I1)
I3: MUL R1, R6, R7 (Writes R1 — WAW with I1, WAR with I2)
I3 cannot execute before I2 reads R1 (WAR). I3 cannot execute before I1 writes R1 (WAW). But I3 doesn't actually need I1's result — it just happens to reuse the name "R1".
The Solution (Register Renaming):
The hardware maintains a Rename Table that maps each architectural register to a physical register. Every instruction that writes to a register gets a new, unique physical register.
I1: ADD P31, P2, P3 (R1 → P31)
I2: SUB P4, P31, P5 (Still reads P31 — RAW preserved)
I3: MUL P32, P6, P7 (R1 → P32, a NEW physical register)
Now:
ILP Impact: By eliminating false dependencies, register renaming dramatically increases the number of instructions that can execute in parallel, unlocking ILP that was hidden by the limited number of architectural register names.
How Pipeline Hazards Restrict ILP:
Speculative Execution:
Definition: Speculative execution is a technique where the processor predicts the outcome of a branch (using a branch predictor) and begins executing instructions from the predicted path before the branch condition is actually resolved.
How It Contributes to ILP:
The Problem:
Consider a loop where the 4 instructions within a single iteration form a chain of RAW dependencies:
Loop: LOAD R1, 0(R2) ; I1: Load from memory
ADD R1, R1, R3 ; I2: Depends on I1 (RAW)
MUL R1, R1, R4 ; I3: Depends on I2 (RAW)
STORE R1, 0(R2) ; I4: Depends on I3 (RAW)
ADDI R2, R2, 4 ; Increment pointer
BNE R2, R5, Loop ; Branch
Within a single iteration, I1→I2→I3→I4 is a strict serial chain. The ILP within one iteration is effectively 1 (no parallelism).
The Solution — Unrolling by 4:
Loop: LOAD R1, 0(R2) ; Iteration 1
LOAD R6, 4(R2) ; Iteration 2 (INDEPENDENT of R1)
LOAD R7, 8(R2) ; Iteration 3 (INDEPENDENT)
LOAD R8, 12(R2) ; Iteration 4 (INDEPENDENT)
ADD R1, R1, R3 ; Depends on Load 1
ADD R6, R6, R3 ; Depends on Load 2 (INDEPENDENT of ADD R1)
ADD R7, R7, R3 ; Depends on Load 3 (INDEPENDENT)
ADD R8, R8, R3 ; Depends on Load 4 (INDEPENDENT)
MUL R1, R1, R4 ; ...and so on
...
Why This Improves ILP:
General Exam Approach:
Example:
I1: ADD R1, R2, R3 (Writes R1)
I2: SUB R4, R1, R5 (Reads R1 — RAW on I1)
I3: MUL R6, R7, R8 (Independent of I1 and I2)
I4: AND R9, R6, R1 (Reads R6 — RAW on I3, Reads R1 — RAW on I1)
Dependency Analysis:
Issue Schedule (Width = 2):
| Cycle | Slot 1 | Slot 2 |
|---|---|---|
| 1 | I1: ADD R1, R2, R3 | I3: MUL R6, R7, R8 |
| 2 | I2: SUB R4, R1, R5 | (stall — I4 not ready) |
| 3 | I4: AND R9, R6, R1 | — |
Total: 3 cycles for 4 instructions. IPC = 4/3 = 1.33.
Given:
Step 1: Calculate IPC (Instructions Per Cycle)
Step 2: Determine Potential ILP
Step 3: Analyze the Gap
Conclusion: IPC = 0.833. The potential ILP of the architecture is 4, but the actual program only exploits about 21% of it. This illustrates the ILP wall — real programs simply do not have enough independent instructions to fully utilize wide-issue processors.
Interpretation: The question likely means the compiler reorders instructions to eliminate 3 stall cycles per instruction on average from the original pipeline.
Given:
Interpretation A (3 stalls eliminated from total program, not per instruction):
If 3 stall cycles are eliminated from an N-instruction sequence:
For large N, this approaches 2.5 (negligible improvement).
Interpretation B (Stall penalty per hazard reduced by eliminating 3 types of stalls):
If the compiler reduces the stall component from 1.5 to a lower value (e.g., by scheduling away 3 categories of stall):
If all stalls are eliminated: New CPI = 1.0 (the ideal).
Most Likely Intended Answer: If the original CPI includes 1.5 stall cycles and the compiler manages to eliminate all of them → New CPI = 1.0. If the "3 stalls" means the penalty is reduced by 3 stall cycles (not possible since only 1.5 exist), the minimum is still CPI = 1.0.
Under ideal conditions (perfect branch prediction, no cache misses, infinite resources), the achievable ILP is limited solely by True Data Dependencies (RAW dependencies).
Method to Determine ILP:
Example:
I1: LOAD R1, mem ; 1 cycle (assume)
I2: LOAD R2, mem ; 1 cycle (independent of I1)
I3: ADD R3, R1, R2 ; 1 cycle (depends on I1 AND I2)
I4: MUL R4, R3, R5 ; 1 cycle (depends on I3)
I5: LOAD R6, mem ; 1 cycle (independent)
I6: ADD R7, R6, R4 ; 1 cycle (depends on I4 AND I5)
Critical Path: I1 → I3 → I4 → I6 = 4 cycles. Total instructions = 6.
Even with infinite resources, this code can only achieve an IPC of 1.5 due to the chain of true dependencies.
VLIW is a processor architecture where the compiler explicitly packages multiple independent operations into a single, very wide instruction word. The hardware executes all operations within the word simultaneously without performing any runtime dependency checking.
Architecture Details:
Key Characteristics:
Examples: Intel Itanium (IA-64/EPIC), Texas Instruments C6000 DSPs, some embedded and signal processing architectures.
VLIW exploits ILP entirely through static, compile-time analysis and scheduling. The compiler does all the heavy lifting that would otherwise be done by expensive runtime hardware in a superscalar processor.
The Process:
Example VLIW Word (4 slots):
| ADD R1, R2, R3 | MUL R4, R5, R6 | LOAD R7, 0(R8) | BNE R9, Loop |
All four operations execute simultaneously in a single clock cycle.
| Feature | Superscalar | VLIW |
|---|---|---|
| ILP Discovery | Dynamic (by hardware at runtime) | Static (by compiler at compile-time) |
| Hardware Complexity | Very complex (OoO logic, ROB, RS, Rename) | Simple (just multiple functional units) |
| Compiler Complexity | Standard (basic optimizations) | Very complex (must find all ILP) |
| Power Consumption | High (complex control logic) | Lower (simpler control) |
| Binary Compatibility | Excellent (old binaries run on new CPUs) | Poor (must recompile for new hardware) |
| Cache Miss Handling | Good (OoO hides latency dynamically) | Poor (compile-time scheduling can't predict misses) |
| Code Size | Compact (standard ISA) | Large (many NOPs in unfilled slots) |
| Examples | Intel Core, AMD Ryzen, Apple M-series | Intel Itanium, TI C6000 DSPs |
| Market Success | Dominant in general-purpose computing | Niche (DSPs, embedded, GPUs) |
Key Insight: Superscalar won the general-purpose market because it can handle unpredictable runtime behavior (cache misses, data-dependent branches) gracefully. VLIW thrives in domains with predictable, regular computation (signal processing, media encoding) where the compiler can schedule effectively.
Reservation Stations (RS) are specialized hardware buffers placed in front of each functional unit in a dynamically scheduled (out-of-order) processor. They are central to Tomasulo's algorithm and modern superscalar designs.
Structure of a Reservation Station Entry:
| Field | Purpose |
|---|---|
| Op | The operation to perform (ADD, MUL, etc.) |
| Vj, Vk | The actual values of the source operands (if available) |
| Qj, Qk | Tags identifying which RS will produce the operand (if not yet available) |
| Busy | Whether this RS entry is occupied |
Role in OoO Execution:
The Reorder Buffer (ROB) is a circular hardware queue that allows instructions to execute out of order but commit (retire) in strict program order. It is essential for supporting precise exceptions and correct speculative execution.
Structure of an ROB Entry:
| Field | Purpose |
|---|---|
| Instruction Type | Branch, Store, Register Write, etc. |
| Destination | The architectural register or memory address to update |
| Value | The computed result (filled when execution completes) |
| Ready | Whether execution has completed |
How It Works:
Why This Preserves Order:
Because the head pointer only advances sequentially, instructions always commit in program order, even though they may have completed execution in any order. If an older instruction causes an exception, all younger instructions (behind it in the ROB) are simply discarded, preserving a precise machine state.
Dynamic Scheduling is a hardware technique where the processor rearranges the order of instruction execution at runtime to reduce stalls and maximize functional unit utilization.
Key Difference from Static Scheduling:
How Dynamic Scheduling Supports ILP:
Implementation: Dynamic scheduling is implemented using Tomasulo's algorithm (Reservation Stations + CDB) or Scoreboarding (an earlier, simpler approach). Modern processors combine dynamic scheduling with ROBs for speculative execution.