/* set_row (a, b, i, n) 
 * assumes a[n*n], b[n], 0 <= i < n
 * sets row i of a to b
 */
void set_row_1 (double* a, double* b, long i, long n) {
  long j;
  for (j = 0; j < n; j++)
    a[i*n+j] = b[j];
}

/* code motion */
/* hoist loop invariant multiplication i*n out of loop */
/* compilers will often do this for simple expressions (here: i*n) */
void set_row_2 (double* a, double* b, long i, long n) {
  long j;
  long k = i*n;
  for (j = 0; j < n; j++)
    a[k+j] = b[j];
}

/* lower(char* s)
 * converts all characters A-Z in string s to lower case
 */
void lower_1 (char* s) {
  int i;
  for (i = 0; i < strlen(s); i++)
    if (s[i] >= 'A' && s[i] <= 'Z')
      s[i] -= 'A'-'a';
}

/* code motion */
/* hoist "strlen(s)" out of loop */
/* safe here since "strlen(s)" has no side effect */
/* compilers never do this since they do not see that strlen has no effect */
void lower_2 (char* s) {
  int i;
  int n = strlen(s);
  for (i = 0; i < n; i++)
    if (s[i] >= 'A' && s[i] <= 'Z')
      s[i] -= 'A'-'a';
}

/* common subexpression elimination */
/* calculate a[i] only once */
/* compilers will pretty reliably do this transformation */
/* also, instead pre-calculating the length we can check for end-of-string */
void lower_3 (char* s) {
  int i;
  char c = 1;			/* pick c = TRUE */
  for (i = 0; c; i++) {		/* could also write: c != 0 */
    c = s[i];
    if (c >= 'A' && c <= 'Z')
      s[i] -= 'A'-'a';
  }
}

/* constant folding */
/* calculate 'A'-'a' at compile time */
/* compilers will reliably do this transformation */
void lower_4 (char* s) {
  int i;
  char c = 1;
  for (i = 0; c; i++) {
    c = s[i];
    if (c >= 'A' && c <= 'Z')
      s[i] -= 0x20;
  }
}

void blur_1 (double* a, double* b, long n) {
  long i,j;
  for (i = 1; i < n-1; i++)
    for (j = 1; j < n-1; j++)
      b[i*n+j] = (5*a[i*n+j] +
		  a[(i-1)*n+j] +
		  a[i*n+(j-1)] +
		  a[(i+1)*n+j] +
		  a[i*n+(j+1)])/9;
}

/* common subexpression elimination */
/* enabled by arithmetic rewrites */
/* legal here, but tricky for floating point code */
void blur_2 (double* a, double* b, long n) {
  long i,j,k;
  for (i = 1; i < n-1; i++)
    for (j = 1; j < n-1; j++)
      k = n*i+j;
      b[k] = (5*a[k] +
	      a[k-n] +
	      a[k-1] +
	      a[k+n] +
	      a[k+1])/9;
}
/* further optimization are possible from here on... */
