/* Test of origin tracking through floating point code and in the case
   where there are large amounts of uninitialised data floating
   around.  This program creates 3 matrices of 2300x2300 doubles,
   makes one value in them undefined, does arithmetic, and tests the
   result, which is then undefined.

   This also tests the secondary otag cache (ocacheL2), since the
   amount of uninitialised data is somewhat over 43MB and it appears
   that quite a lot of non-zero-otag lines are pushed into ocacheL2.

   This program needs to be compiled with -O.
*/

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "../memcheck.h"


double** alloc_square_array ( int nArr )
{
  int i;
  double** vec;
  assert(nArr >= 1);
  vec = malloc(nArr * sizeof(double*));
  assert(vec);
  for (i = 0; i < nArr; i++) {
    vec[i] = malloc(nArr * sizeof(double));
    assert(vec);
  }
  return vec;
}

double** do3x3smooth ( double** arr, int nArr )
{
  int i, j;
  double** out;
  assert(nArr >= 3);
  out = alloc_square_array(nArr - 2);
  assert(out);
  for (i = 1; i < nArr-1; i++) {
    for (j = 1; j < nArr-1; j++) {
      double s =   arr[i-1][j-1] + arr[i-1][j  ] + arr[i-1][j+1]
                 + arr[i  ][j-1] + arr[i  ][j  ] + arr[i  ][j+1]
                 + arr[i+1][j-1] + arr[i+1][j  ] + arr[i+1][j+1];
      out[i-1][j-1] = s / 9.0;
    }
  }
  return out;
}

double sum ( double** arr, int nArr )
{
  int i, j;
  double s = 0.0;
  assert(nArr >= 1);
  for (i = 0; i < nArr; i++) {
    for (j = 0; j < nArr; j++) {
      s += arr[i][j];
    }
  }
  return s;
}

void setup_arr ( /*OUT*/double** arr, int nArr )
{
  int i, j;
  assert(nArr >= 1);
  for (i = 0; i < nArr; i++) {
    for (j = 0; j < nArr; j++) {
      arr[i][j] = (double)(i * j);
      if (i == nArr/2 && j == nArr/2) {
         unsigned char* p = (unsigned char*)&arr[i][j];
         (void) VALGRIND_MAKE_MEM_UNDEFINED(p, 1);
      }
    }
  }
}

int main ( void )
{
  int nArr = 2300;
  int ri;
  double r, **arr, **arr2, **arr3;
  arr = alloc_square_array(nArr);
  setup_arr( arr, nArr );
  arr2 = do3x3smooth( arr, nArr );
  arr3 = do3x3smooth( arr2, nArr-2 );
  r = sum( arr3, nArr-4 );
  /* Convert answer to int before testing it, so as to
     guarantee there's only one conditional branch. */
  if (0) fprintf(stderr, "r = %g\n", r );
  r /= 10000.0;
  ri = (int)r;
  if (0) fprintf(stderr, "ri = %d\n", ri);
  if (ri == 696565111) {
     fprintf(stderr, "Test succeeded.\n");
  } else {
     fprintf(stderr, "Test FAILED !\n");
     assert(0);
  }
  return 0;
}