Homework 4

Published on October 14, 2025

problem 1

a.)

Show all the data, anti and output dependence. Note: dependent instructions may not be next to each other.

Data (RAW)

An instruction needs to read a value that a previous instruction writes. This is a “true” dependency because the actual data is being passed between instructions.

i1 → i2: i1 writes f0, i2 reads f0
i2 → i4: i2 writes f4, i4 reads f4
i3 → i4: i3 writes f6, i4 reads f6
i4 → i5: i4 writes f6, i5 reads f6
i6 → i8: i6 writes x1, i8 reads x1
i8 → i9: i8 writes x4, i9 reads x4

i6 → i1 (next iteration): i6 writes x1, i1 reads x1
i7 → i3 (next iteration): i7 writes x2, i3 reads x2
i7 → i5 (next iteration): i7 writes x2, i5 reads x2

Anti (WAR)

An instruction wants to write to a register or memory location that a previous instruction is still scheduled to read

i1 → i6: i1 reads x1, i6 writes x1
i3 → i7: i3 reads x2, i7 writes x2
i5 → i7: i5 reads x2, i7 writes x2

i2 → i1 (next iteration): i2 reads f0, i1 writes f0
i4 → i2 (next iteration): i4 reads f4, i2 writes f4
i5 → i4 (next iteration): i5 reads f6, i4 writes f6

Output (WAW)

Two instructions write to the same register or memory location. Within a Single Loop Iteration:

i3 → i4: i3 writes to f6, i4 writes to f6

b.)

Assume a single-issue pipeline. Show how the loop would look both unscheduled by the compiler and after compiler scheduling, including any stalls or idle clock cycles. What is the execution time (in cycles) per element of the result vector Y, unscheduled and scheduled?

Unscheduled

Clock CycleInstruction ExecutingReason for stall
1fld f0, 0(x1)
2stallfmul.d need the result of fld f0
3fmul.d f4, f0, f2
4fld f6, 0(x2)
5stallfadd.d needs the result of fmul.d. The latency is 8 cycles
6stall
7stall
8stall
9stall
10stall
11stall(7 stalls + the fld at cycle 4 fill the 8 cycle latency)
12fadd.d f6, f4, f6The result of fmul.d is now ready. The result of fld f6 is also ready
13stallfsd needs the result of fadd.d. Latency = 4 cycles
14stall
15stall
16stall
17fsd f6, 0(x2)
18addi x1, x1 8
19addi x2, x2, 8
20sltu x4, x1, x3
21stallbnez needs the result of sltu.
22bnez x4, fooLoop iteration ends
  • The total execution time for one element of the vector Y is 22 clock cycles.

Scheduled

Clock CycleInstruction ExecutingComment
1fld f0, 0(x1)
2fld f6, 0(x2)Move the second load up
3fmul.d f4, f0, f2
4addi x1, x1 8Fill stall with independent operation
5sltu x4, x1, x3Fill another stall slot
6stallmust wait for fmul.d to finish
7stall
8stall
9stall
10stall
11stall
12fadd.d f6, f4, f6
13stall
14stall
15stall
16stall
17fsd f6, 0(x2)
18addi x2, x2, 8
19bnez x4, fooLoop iteration ends
  • The total execution time for one element of the vector Y is 19 clock cycles.

c.)

Assume a single-issue pipeline. Unroll the loop by a factor of 4 to schedule it without any stalls, collapsing the loop overhead instructions. Show the unrolled and scheduled instruction sequence. What is the execution time per element of the result? You can assume that the number of iterations is always a multiple of the unrolled loop body.

Clock CycleInstruction ExecutingComment
1fld f0, 0(x1)Load the first X element
2fld f6, 0(x2)Load the second X element
3fld f20, 16(x1)Load the third X element
4fld f30, 24(x1)Load the fourht X element
5fmul.d f4, f0, f2First fld is done. Start the first multiply. This begins an 8-cycle latency window.
6fmul.d f14, f10, f2Second fld is done. Start second multiply
7fmul.d f24, f20, f2Third fld is done. Start third multiply
8fmul.d f34, f30, f2Fourth fld is done. Start fourth multiply
9fld f6, 0(x2)Fill the fmul delay slots by loading the Y values
10fld f16, 8(x2)
11fld f26, 16(x2)
12fld f36, 24(x2)
13addi x1, x1, 32Last slot in the first fmul latency window. Update the X pointer
14fadd.d f8, f4, f6First fmul result is ready. Start the first add. This begins 4-cycle latency window
15fadd.d f18, f14, f16start second add
16fadd.d f28, f24, f26start third add
17fadd.d f38, f34, f36start fourth add
18addi x2, x2, 32Fill fadd delay slot. Update the Y pointer before the stores
19sltu x4, x1, x3Fill another fadd delay slot
20fsd f8, -32(x2)First fadd is done. Store result using new x2 pointer
21fsd f18, -24(x2)Second fadd is done.
22fsd f28, -16(x2)Third fadd is done.
23fsd f38, -8(x2)Fourth fadd is done.
24bnez x4, fooBranch. The latency from sltu (cycle 19) is met.
  • The unrolled and scheduled loop processes 4 elements in a total of 24 cycles

Execution time per element = Total Cycles / Number of Elements = 24 / 4 = 6 cycles

problem 1

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

// Define the size of the arrays
#define N 200000

// Function to get the current time in seconds
double get_time() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec + tv.tv_usec / 1000000.0;
}


int main() {
    // Using static to avoid stack overflow for large arrays
    static double x[N], y[N], y_unrolled[N];
    double a;

    // Initialize arrays with random numbers
    for (int i = 0; i < N; i++) {
        x[i] = (double)rand() / RAND_MAX;
        y[i] = (double)rand() / RAND_MAX;

        y_unrolled[i] = y[i];
    }
    a = (double)rand() / RAND_MAX;

    printf("Starting DAXPY benchmark with N = %d\n", N);

    double start_time = get_time();

    for (int i = 0; i < N; i++) { 
        y[i] = a * x[i] + y[i];   
    }

    double end_time = get_time();
    double standard_loop_time = end_time - start_time;
    printf("Standard loop execution time:   %f seconds\n", standard_loop_time);

    start_time = get_time();

    // Loop unrolled by a factor of 4 
    for (int i = 0; i < N; i += 4) {
        y_unrolled[i]   = a * x[i]   + y_unrolled[i];
        y_unrolled[i+1] = a * x[i+1] + y_unrolled[i+1];
        y_unrolled[i+2] = a * x[i+2] + y_unrolled[i+2];
        y_unrolled[i+3] = a * x[i+3] + y_unrolled[i+3];
    }

    end_time = get_time();
    double unrolled_loop_time = end_time - start_time;
    printf("Unrolled loop execution time:   %f seconds\n", unrolled_loop_time);

    printf("\nComparison:\n");
    printf("The unrolled loop was %.2f times faster.\n", standard_loop_time / unrolled_loop_time);

    return 0;
}
Starting DAXPY benchmark with N = 200000
Standard loop execution time:   0.000348 seconds
Unrolled loop execution time:   0.000257 seconds

Comparison:
The unrolled loop was 1.35 times faster.