A2 - pipelines

stages

int N = 1000;
double A[N];  /* static arrya */

< some code >

for (i = 0; i < N; i++) {
	A[i] = A[i] * A[i];
}

< more code >
// a 'normal' code to sum over an array
double A[1000];

sum = 0.0;
for (i = 0; i < N; i++) {
	sum += A[i];
}
// slow as each increment of the sum cannot begin until the previous result is known


// optimise: unrolling the loop
double A[1000];

t1 = 0.0;
t2 = 0.0;
t3 = 0.0;
t4 = 0.0;
t5 = 0.0;

for (i = 0; i < N; i +=5) {
	t1 += A[i];
	t2 += A[i+1];
	t3 += A[i+2];
	t4 += A[i+3];
	t5 += A[i+4];
}
sum = t1 + t2 + t3 + t4 + t5
// 5x faster
int N = 1000;
double A[N];
int j:

< set j >

sum = 0.0
for (i = 0; i < N-j; i++) {
	sum += A[i] + A[i+j]
}

branches

double A[N], B[N];

for (i=0; i<N; i++) {
    if (i==0) {              /* LH Boundary */
        B[i] = 0.5*(A[N-1] + A[i+1]);
    } else if (i==N-1) {     /* RH Boundary */
        B[i] = 0.5*(A[i-1] + A[0]);
    } else {                 /* All others */
        B[i] = 0.5*(A[i-1] + A[i+1]);
    }
}
double A[N], B[N];

/* LH Boundary */
B[0] = 0.5*(A[N-1] + A[1]);

/* All others */
for (i=1; i<N-1; i++) {
    B[i] = 0.5*(A[i-1] + A[i+1]);
}

/* RH Boundary */
B[N-1] = 0.5*(A[N-2] + A[0]);

iL = (i + N - 1) % N;
iR = (i + N + 1) % N;
```
- padding the array by 2 per direction to include 'halo' elements that are duplicates of those on the opposite edge, so the points are valid even at the boundaries

iL = i - 1;
iR = i + 1