/*
    Copyright 2007-2008 Adobe Systems Incorporated
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
    or a copy at http://stlab.adobe.com/licenses.html )


Goal:  Test compiler optimizations related to simple language defined types

Assumptions:

	1) the compiler will move loop invariant calculations on simple types out of a loop
		aka: loop invariant code motion
		
		for (i = 0; i < N; ++i)						temp = A + B + C + D;
			result = input[i] + A+B+C+D;	==>		for (i = 0; i < N; ++i)
														result = input[i] + temp;

*/

/******************************************************************************/

#include "benchmark_stdint.hpp"
#include <cstddef>
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cmath>
#include "benchmark_results.h"
#include "benchmark_timer.h"

/******************************************************************************/

// this constant may need to be adjusted to give reasonable minimum times
// For best results, times should be about 1.0 seconds for the minimum test run
int iterations = 200000;


// 8000 items, or between 8k and 64k of data
// this is intended to remain within the L2 cache of most common CPUs
const int MYSIZE = 8000;


// initial value for filling our arrays, may be changed from the command line
double init_value = 1.0;

/******************************************************************************/

// our global arrays of numbers to be operated upon

double dataDouble[MYSIZE];
float dataFloat[MYSIZE];

uint64_t data64unsigned[MYSIZE];
int64_t data64[MYSIZE];

uint32_t data32unsigned[MYSIZE];
int32_t data32[MYSIZE];

uint16_t data16unsigned[MYSIZE];
int16_t data16[MYSIZE];

uint8_t data8unsigned[MYSIZE];
int8_t data8[MYSIZE];

/******************************************************************************/

#include "benchmark_shared_tests.h"

/******************************************************************************/

// v1 is constant in the function, so we can move the addition or subtraction of it outside the loop entirely
// converting it to a multiply and a summation of the input array
// Note that this is always legal for integers
// it can only be applied to floating point if using inexact math (relaxed IEEE rules)
template <typename T, typename Shifter>
void test_hoisted_variable1(T* first, int count, T v1, const char *label) {
  int i;
  
  start_timer();
  
  for(i = 0; i < iterations; ++i) {
    T result = 0;
    for (int n = 0; n < count; ++n) {
		result += first[n];
	}
	result += count * v1;
    check_shifted_variable_sum<T, Shifter>(result, v1);
  }
  
  record_result( timer(), label );
}

/******************************************************************************/


//int main(int argc, char** argv)
void DoLoopInvariantTests(const int iLoops)
{
	double temp = 1.0;

/*
	// output command for documentation:
	int i;
	for (i = 0; i < argc; ++i)
		printf("%s ", argv[i] );
	printf("\n");

	if (argc > 1) iterations = atoi(argv[1]);
	if (argc > 2) init_value = (double) atof(argv[2]);
	if (argc > 3) temp = (double)atof(argv[3]);
*/

	iterations = iLoops;

// int8_t
	::fill(data8, data8+MYSIZE, int8_t(init_value));
	int8_t var1int8_1, var1int8_2, var1int8_3, var1int8_4;
	var1int8_1 = int8_t(temp);
	var1int8_2 = var1int8_1 * int8_t(2);
	var1int8_3 = var1int8_1 + int8_t(2);
	var1int8_4 = var1int8_1 + var1int8_2 / var1int8_3;
	
	// test moving redundant calcs out of loop
	test_variable1< int8_t, custom_add_variable<int8_t> > (data8, MYSIZE, var1int8_1, "int8_t variable add");
	test_hoisted_variable1< int8_t, custom_add_variable<int8_t> > (data8, MYSIZE, var1int8_1, "int8_t variable add hoisted");
	test_variable4< int8_t, custom_add_multiple_variable<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable adds");

	test_variable1< int8_t, custom_sub_variable<int8_t> > (data8, MYSIZE, var1int8_1, "int8_t variable subtract");
	test_variable4< int8_t, custom_sub_multiple_variable<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable subtracts");
	
	test_variable1< int8_t, custom_multiply_variable<int8_t> > (data8, MYSIZE, var1int8_1, "int8_t variable multiply");
	test_variable4< int8_t, custom_multiply_multiple_variable<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable multiplies");
	test_variable4< int8_t, custom_multiply_multiple_variable2<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable multiplies2");

	test_variable1< int8_t, custom_divide_variable<int8_t> > (data8, MYSIZE, var1int8_1, "int8_t variable divide");
	test_variable4< int8_t, custom_divide_multiple_variable<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable divides");
	test_variable4< int8_t, custom_divide_multiple_variable2<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable divides2");
	
	test_variable4< int8_t, custom_mixed_multiple_variable<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable mixed");

	test_variable1< int8_t, custom_variable_and<int8_t> > (data8, MYSIZE, var1int8_1, "int8_t variable and");
	test_variable4< int8_t, custom_multiple_variable_and<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable and");

	test_variable1< int8_t, custom_variable_or<int8_t> > (data8, MYSIZE, var1int8_1, "int8_t variable or");
	test_variable4< int8_t, custom_multiple_variable_or<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable or");

	test_variable1< int8_t, custom_variable_xor<int8_t> > (data8, MYSIZE, var1int8_1, "int8_t variable xor");
	test_variable4< int8_t, custom_multiple_variable_xor<int8_t> > (data8, MYSIZE, var1int8_1, var1int8_2, var1int8_3, var1int8_4, "int8_t multiple variable xor");
	
//	summarize("int8_t loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );


// unsigned8
	::fill(data8unsigned, data8unsigned+MYSIZE, uint8_t(init_value));
	uint8_t var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4;
	var1uint8_1 = uint8_t(temp);
	var1uint8_2 = var1uint8_1 * uint8_t(2);
	var1uint8_3 = var1uint8_1 + uint8_t(2);
	var1uint8_4 = var1uint8_1 + var1uint8_2 / var1uint8_3;
	
	// test moving redundant calcs out of loop
	test_variable1< uint8_t, custom_add_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, "uint8_t variable add");
	test_hoisted_variable1< uint8_t, custom_add_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, "uint8_t variable add hoisted");
	test_variable4< uint8_t, custom_add_multiple_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable adds");

	test_variable1< uint8_t, custom_sub_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, "uint8_t variable subtract");
	test_variable4< uint8_t, custom_sub_multiple_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable subtracts");
	
	test_variable1< uint8_t, custom_multiply_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, "uint8_t variable multiply");
	test_variable4< uint8_t, custom_multiply_multiple_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable multiplies");
	test_variable4< uint8_t, custom_multiply_multiple_variable2<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable multiplies2");

	test_variable1< uint8_t, custom_divide_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, "uint8_t variable divide");
	test_variable4< uint8_t, custom_divide_multiple_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable divides");
	test_variable4< uint8_t, custom_divide_multiple_variable2<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable divides2");
	
	test_variable4< uint8_t, custom_mixed_multiple_variable<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable mixed");

	test_variable1< uint8_t, custom_variable_and<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, "uint8_t variable and");
	test_variable4< uint8_t, custom_multiple_variable_and<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable and");

	test_variable1< uint8_t, custom_variable_or<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, "uint8_t variable or");
	test_variable4< uint8_t, custom_multiple_variable_or<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable or");

	test_variable1< uint8_t, custom_variable_xor<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, "uint8_t variable xor");
	test_variable4< uint8_t, custom_multiple_variable_xor<uint8_t> > (data8unsigned, MYSIZE, var1uint8_1, var1uint8_2, var1uint8_3, var1uint8_4, "uint8_t multiple variable xor");
	
//	summarize("uint8_t loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );


// int16_t
	::fill(data16, data16+MYSIZE, int16_t(init_value));
	int16_t var1int16_1, var1int16_2, var1int16_3, var1int16_4;
	var1int16_1 = int16_t(temp);
	var1int16_2 = var1int16_1 * int16_t(2);
	var1int16_3 = var1int16_1 + int16_t(2);
	var1int16_4 = var1int16_1 + var1int16_2 / var1int16_3;

	// test moving redundant calcs out of loop
	test_variable1< int16_t, custom_add_variable<int16_t> > (data16, MYSIZE, var1int16_1, "int16_t variable add");
	test_hoisted_variable1< int16_t, custom_add_variable<int16_t> > (data16, MYSIZE, var1int16_1, "int16_t variable add hoisted");
	test_variable4< int16_t, custom_add_multiple_variable<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable adds");

	test_variable1< int16_t, custom_sub_variable<int16_t> > (data16, MYSIZE, var1int16_1, "int16_t variable subtract");
	test_variable4< int16_t, custom_sub_multiple_variable<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable subtracts");
	
	test_variable1< int16_t, custom_multiply_variable<int16_t> > (data16, MYSIZE, var1int16_1, "int16_t variable multiply");
	test_variable4< int16_t, custom_multiply_multiple_variable<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable multiplies");
	test_variable4< int16_t, custom_multiply_multiple_variable2<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable multiplies2");

	test_variable1< int16_t, custom_divide_variable<int16_t> > (data16, MYSIZE, var1int16_1, "int16_t variable divide");
	test_variable4< int16_t, custom_divide_multiple_variable<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable divides");
	test_variable4< int16_t, custom_divide_multiple_variable2<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable divides2");
	
	test_variable4< int16_t, custom_mixed_multiple_variable<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable mixed");

	test_variable1< int16_t, custom_variable_and<int16_t> > (data16, MYSIZE, var1int16_1, "int16_t variable and");
	test_variable4< int16_t, custom_multiple_variable_and<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable and");

	test_variable1< int16_t, custom_variable_or<int16_t> > (data16, MYSIZE, var1int16_1, "int16_t variable or");
	test_variable4< int16_t, custom_multiple_variable_or<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable or");

	test_variable1< int16_t, custom_variable_xor<int16_t> > (data16, MYSIZE, var1int16_1, "int16_t variable xor");
	test_variable4< int16_t, custom_multiple_variable_xor<int16_t> > (data16, MYSIZE, var1int16_1, var1int16_2, var1int16_3, var1int16_4, "int16_t multiple variable xor");
	
//	summarize("int16_t loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );


// unsigned16
	::fill(data16unsigned, data16unsigned+MYSIZE, uint16_t(init_value));
	uint16_t var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4;
	var1uint16_1 = uint16_t(temp);
	var1uint16_2 = var1uint16_1 * uint16_t(2);
	var1uint16_3 = var1uint16_1 + uint16_t(2);
	var1uint16_4 = var1uint16_1 + var1uint16_2 / var1uint16_3;

	// test moving redundant calcs out of loop
	test_variable1< uint16_t, custom_add_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, "uint16_t variable add");
	test_hoisted_variable1< uint16_t, custom_add_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, "uint16_t variable add hoisted");
	test_variable4< uint16_t, custom_add_multiple_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable adds");

	test_variable1< uint16_t, custom_sub_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, "uint16_t variable subtract");
	test_variable4< uint16_t, custom_sub_multiple_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable subtracts");
	
	test_variable1< uint16_t, custom_multiply_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, "uint16_t variable multiply");
	test_variable4< uint16_t, custom_multiply_multiple_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable multiplies");
	test_variable4< uint16_t, custom_multiply_multiple_variable2<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable multiplies2");

	test_variable1< uint16_t, custom_divide_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, "uint16_t variable divide");
	test_variable4< uint16_t, custom_divide_multiple_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable divides");
	test_variable4< uint16_t, custom_divide_multiple_variable2<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable divides2");
	
	test_variable4< uint16_t, custom_mixed_multiple_variable<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable mixed");

	test_variable1< uint16_t, custom_variable_and<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, "uint16_t variable and");
	test_variable4< uint16_t, custom_multiple_variable_and<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable and");

	test_variable1< uint16_t, custom_variable_or<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, "uint16_t variable or");
	test_variable4< uint16_t, custom_multiple_variable_or<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable or");

	test_variable1< uint16_t, custom_variable_xor<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, "uint16_t variable xor");
	test_variable4< uint16_t, custom_multiple_variable_xor<uint16_t> > (data16unsigned, MYSIZE, var1uint16_1, var1uint16_2, var1uint16_3, var1uint16_4, "uint16_t multiple variable xor");
	
//	summarize("uint16_t loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );


// int32_t
	::fill(data32, data32+MYSIZE, int32_t(init_value));
	int32_t var1int32_1, var1int32_2, var1int32_3, var1int32_4;
	var1int32_1 = int32_t(temp);
	var1int32_2 = var1int32_1 * int32_t(2);
	var1int32_3 = var1int32_1 + int32_t(2);
	var1int32_4 = var1int32_1 + var1int32_2 / var1int32_3;

	// test moving redundant calcs out of loop
	test_variable1< int32_t, custom_add_variable<int32_t> > (data32, MYSIZE, var1int32_1, "int32_t variable add");
	test_hoisted_variable1< int32_t, custom_add_variable<int32_t> > (data32, MYSIZE, var1int32_1, "int32_t variable add hoisted");
	test_variable4< int32_t, custom_add_multiple_variable<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable adds");

	test_variable1< int32_t, custom_sub_variable<int32_t> > (data32, MYSIZE, var1int32_1, "int32_t variable subtract");
	test_variable4< int32_t, custom_sub_multiple_variable<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable subtracts");
	
	test_variable1< int32_t, custom_multiply_variable<int32_t> > (data32, MYSIZE, var1int32_1, "int32_t variable multiply");
	test_variable4< int32_t, custom_multiply_multiple_variable<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable multiplies");
	test_variable4< int32_t, custom_multiply_multiple_variable2<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable multiplies2");

	test_variable1< int32_t, custom_divide_variable<int32_t> > (data32, MYSIZE, var1int32_1, "int32_t variable divide");
	test_variable4< int32_t, custom_divide_multiple_variable<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable divides");
	test_variable4< int32_t, custom_divide_multiple_variable2<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable divides2");
	
	test_variable4< int32_t, custom_mixed_multiple_variable<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable mixed");

	test_variable1< int32_t, custom_variable_and<int32_t> > (data32, MYSIZE, var1int32_1, "int32_t variable and");
	test_variable4< int32_t, custom_multiple_variable_and<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable and");

	test_variable1< int32_t, custom_variable_or<int32_t> > (data32, MYSIZE, var1int32_1, "int32_t variable or");
	test_variable4< int32_t, custom_multiple_variable_or<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable or");

	test_variable1< int32_t, custom_variable_xor<int32_t> > (data32, MYSIZE, var1int32_1, "int32_t variable xor");
	test_variable4< int32_t, custom_multiple_variable_xor<int32_t> > (data32, MYSIZE, var1int32_1, var1int32_2, var1int32_3, var1int32_4, "int32_t multiple variable xor");
	
//	summarize("int32_t loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );


// unsigned32
	::fill(data32unsigned, data32unsigned+MYSIZE, uint32_t(init_value));
	uint32_t var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4;
	var1uint32_1 = uint32_t(temp);
	var1uint32_2 = var1uint32_1 * uint32_t(2);
	var1uint32_3 = var1uint32_1 + uint32_t(2);
	var1uint32_4 = var1uint32_1 + var1uint32_2 / var1uint32_3;
	
	// test moving redundant calcs out of loop
	test_variable1< uint32_t, custom_add_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, "uint32_t variable add");
	test_hoisted_variable1< uint32_t, custom_add_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, "uint32_t variable add hoisted");
	test_variable4< uint32_t, custom_add_multiple_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable adds");

	test_variable1< uint32_t, custom_sub_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, "uint32_t variable subtract");
	test_variable4< uint32_t, custom_sub_multiple_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable subtracts");
	
	test_variable1< uint32_t, custom_multiply_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, "uint32_t variable multiply");
	test_variable4< uint32_t, custom_multiply_multiple_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable multiplies");
	test_variable4< uint32_t, custom_multiply_multiple_variable2<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable multiplies2");

	test_variable1< uint32_t, custom_divide_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, "uint32_t variable divide");
	test_variable4< uint32_t, custom_divide_multiple_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable divides");
	test_variable4< uint32_t, custom_divide_multiple_variable2<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable divides2");
	
	test_variable4< uint32_t, custom_mixed_multiple_variable<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable mixed");

	test_variable1< uint32_t, custom_variable_and<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, "uint32_t variable and");
	test_variable4< uint32_t, custom_multiple_variable_and<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable and");

	test_variable1< uint32_t, custom_variable_or<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, "uint32_t variable or");
	test_variable4< uint32_t, custom_multiple_variable_or<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable or");

	test_variable1< uint32_t, custom_variable_xor<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, "uint32_t variable xor");
	test_variable4< uint32_t, custom_multiple_variable_xor<uint32_t> > (data32unsigned, MYSIZE, var1uint32_1, var1uint32_2, var1uint32_3, var1uint32_4, "uint32_t multiple variable xor");
	
//	summarize("uint32_t loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );
	

// int64_t
	::fill(data64, data64+MYSIZE, int64_t(init_value));
	int64_t var1int64_1, var1int64_2, var1int64_3, var1int64_4;
	var1int64_1 = int64_t(temp);
	var1int64_2 = var1int64_1 * int64_t(2);
	var1int64_3 = var1int64_1 + int64_t(2);
	var1int64_4 = var1int64_1 + var1int64_2 / var1int64_3;

	// test moving redundant calcs out of loop
	test_variable1< int64_t, custom_add_variable<int64_t> > (data64, MYSIZE, var1int64_1, "int64_t variable add");
	test_hoisted_variable1< int64_t, custom_add_variable<int64_t> > (data64, MYSIZE, var1int64_1, "int64_t variable add hoisted");
	test_variable4< int64_t, custom_add_multiple_variable<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable adds");

	test_variable1< int64_t, custom_sub_variable<int64_t> > (data64, MYSIZE, var1int64_1, "int64_t variable subtract");
	test_variable4< int64_t, custom_sub_multiple_variable<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable subtracts");
	
	test_variable1< int64_t, custom_multiply_variable<int64_t> > (data64, MYSIZE, var1int64_1, "int64_t variable multiply");
	test_variable4< int64_t, custom_multiply_multiple_variable<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable multiplies");
	test_variable4< int64_t, custom_multiply_multiple_variable2<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable multiplies2");

	test_variable1< int64_t, custom_divide_variable<int64_t> > (data64, MYSIZE, var1int64_1, "int64_t variable divide");
	test_variable4< int64_t, custom_divide_multiple_variable<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable divides");
	test_variable4< int64_t, custom_divide_multiple_variable2<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable divides2");
	
	test_variable4< int64_t, custom_mixed_multiple_variable<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable mixed");

	test_variable1< int64_t, custom_variable_and<int64_t> > (data64, MYSIZE, var1int64_1, "int64_t variable and");
	test_variable4< int64_t, custom_multiple_variable_and<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable and");

	test_variable1< int64_t, custom_variable_or<int64_t> > (data64, MYSIZE, var1int64_1, "int64_t variable or");
	test_variable4< int64_t, custom_multiple_variable_or<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable or");

	test_variable1< int64_t, custom_variable_xor<int64_t> > (data64, MYSIZE, var1int64_1, "int64_t variable xor");
	test_variable4< int64_t, custom_multiple_variable_xor<int64_t> > (data64, MYSIZE, var1int64_1, var1int64_2, var1int64_3, var1int64_4, "int64_t multiple variable xor");
	
//	summarize("int64_t loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );


// unsigned64
	::fill(data64unsigned, data64unsigned+MYSIZE, uint64_t(init_value));
	uint64_t var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4;
	var1uint64_1 = uint64_t(temp);
	var1uint64_2 = var1uint64_1 * uint64_t(2);
	var1uint64_3 = var1uint64_1 + uint64_t(2);
	var1uint64_4 = var1uint64_1 + var1uint64_2 / var1uint64_3;

	// test moving redundant calcs out of loop
	test_variable1< uint64_t, custom_add_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, "uint64_t variable add");
	test_hoisted_variable1< uint64_t, custom_add_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, "uint64_t variable add hoisted");
	test_variable4< uint64_t, custom_add_multiple_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable adds");

	test_variable1< uint64_t, custom_sub_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, "uint64_t variable subtract");
	test_variable4< uint64_t, custom_sub_multiple_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable subtracts");
	
	test_variable1< uint64_t, custom_multiply_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, "uint64_t variable multiply");
	test_variable4< uint64_t, custom_multiply_multiple_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable multiplies");
	test_variable4< uint64_t, custom_multiply_multiple_variable2<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable multiplies2");

	test_variable1< uint64_t, custom_divide_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, "uint64_t variable divide");
	test_variable4< uint64_t, custom_divide_multiple_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable divides");
	test_variable4< uint64_t, custom_divide_multiple_variable2<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable divides2");
	
	test_variable4< uint64_t, custom_mixed_multiple_variable<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable mixed");

	test_variable1< uint64_t, custom_variable_and<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, "uint64_t variable and");
	test_variable4< uint64_t, custom_multiple_variable_and<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable and");

	test_variable1< uint64_t, custom_variable_or<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, "uint64_t variable or");
	test_variable4< uint64_t, custom_multiple_variable_or<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable or");

	test_variable1< uint64_t, custom_variable_xor<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, "uint64_t variable xor");
	test_variable4< uint64_t, custom_multiple_variable_xor<uint64_t> > (data64unsigned, MYSIZE, var1uint64_1, var1uint64_2, var1uint64_3, var1uint64_4, "uint64_t multiple variable xor");
	
//	summarize("uint64_t loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );



// float
	::fill(dataFloat, dataFloat+MYSIZE, float(init_value));
	float var1Float_1, var1Float_2, var1Float_3, var1Float_4;
	var1Float_1 = float(temp);
	var1Float_2 = var1Float_1 * float(2.0);
	var1Float_3 = var1Float_1 + float(2.0);
	var1Float_4 = var1Float_1 + var1Float_2 / var1Float_3;

	// test moving redundant calcs out of loop
	test_variable1< float, custom_add_variable<float> > (dataFloat, MYSIZE, var1Float_1, "float variable add");
	test_hoisted_variable1< float, custom_add_variable<float> > (dataFloat, MYSIZE, var1Float_1, "float variable add hoisted");
	test_variable4< float, custom_add_multiple_variable<float> > (dataFloat, MYSIZE, var1Float_1, var1Float_2, var1Float_3, var1Float_4, "float multiple variable adds");

	test_variable1< float, custom_sub_variable<float> > (dataFloat, MYSIZE, var1Float_1, "float variable subtract");
	test_variable4< float, custom_sub_multiple_variable<float> > (dataFloat, MYSIZE, var1Float_1, var1Float_2, var1Float_3, var1Float_4, "float multiple variable subtracts");
	
	test_variable1< float, custom_multiply_variable<float> > (dataFloat, MYSIZE, var1Float_1, "float variable multiply");
	test_variable4< float, custom_multiply_multiple_variable<float> > (dataFloat, MYSIZE, var1Float_1, var1Float_2, var1Float_3, var1Float_4, "float multiple variable multiplies");
	test_variable4< float, custom_multiply_multiple_variable2<float> > (dataFloat, MYSIZE, var1Float_1, var1Float_2, var1Float_3, var1Float_4, "float multiple variable multiplies2");

	test_variable1< float, custom_divide_variable<float> > (dataFloat, MYSIZE, var1Float_1, "float variable divide");
	test_variable4< float, custom_divide_multiple_variable<float> > (dataFloat, MYSIZE, var1Float_1, var1Float_2, var1Float_3, var1Float_4, "float multiple variable divides");
	test_variable4< float, custom_divide_multiple_variable2<float> > (dataFloat, MYSIZE, var1Float_1, var1Float_2, var1Float_3, var1Float_4, "float multiple variable divides2");
	
	test_variable4< float, custom_mixed_multiple_variable<float> > (dataFloat, MYSIZE, var1Float_1, var1Float_2, var1Float_3, var1Float_4, "float multiple variable mixed");
	
//	summarize("float loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );


// double
	::fill(dataDouble, dataDouble+MYSIZE, double(init_value));
	double var1Double_1, var1Double_2, var1Double_3, var1Double_4;
	var1Double_1 = double(temp);
	var1Double_2 = var1Double_1 * double(2.0);
	var1Double_3 = var1Double_1 + double(2.0);
	var1Double_4 = var1Double_1 + var1Double_2 / var1Double_3;

	// test moving redundant calcs out of loop
	test_variable1< double, custom_add_variable<double> > (dataDouble, MYSIZE, var1Double_1, "double variable add");
	test_hoisted_variable1< double, custom_add_variable<double> > (dataDouble, MYSIZE, var1Double_1, "double variable add hoisted");
	test_variable4< double, custom_add_multiple_variable<double> > (dataDouble, MYSIZE, var1Double_1, var1Double_2, var1Double_3, var1Double_4, "double multiple variable adds");
	
	test_variable1< double, custom_sub_variable<double> > (dataDouble, MYSIZE, var1Double_1, "double variable subtract");
	test_variable4< double, custom_sub_multiple_variable<double> > (dataDouble, MYSIZE, var1Double_1, var1Double_2, var1Double_3, var1Double_4, "double multiple variable subtracts");
	
	test_variable1< double, custom_multiply_variable<double> > (dataDouble, MYSIZE, var1Double_1, "double variable multiply");
	test_variable4< double, custom_multiply_multiple_variable<double> > (dataDouble, MYSIZE, var1Double_1, var1Double_2, var1Double_3, var1Double_4, "double multiple variable multiplies");
	test_variable4< double, custom_multiply_multiple_variable2<double> > (dataDouble, MYSIZE, var1Double_1, var1Double_2, var1Double_3, var1Double_4, "double multiple variable multiplies2");

	test_variable1< double, custom_divide_variable<double> > (dataDouble, MYSIZE, var1Double_1, "double variable divide");
	test_variable4< double, custom_divide_multiple_variable<double> > (dataDouble, MYSIZE, var1Double_1, var1Double_2, var1Double_3, var1Double_4, "double multiple variable divides");
	test_variable4< double, custom_divide_multiple_variable2<double> > (dataDouble, MYSIZE, var1Double_1, var1Double_2, var1Double_3, var1Double_4, "double multiple variable divides2");
	
	test_variable4< double, custom_mixed_multiple_variable<double> > (dataDouble, MYSIZE, var1Double_1, var1Double_2, var1Double_3, var1Double_4, "double multiple variable mixed");
	
//	summarize("double loop invariant", MYSIZE, iterations, kDontShowGMeans, kDontShowPenalty );


//	return 0;
}

// the end
/******************************************************************************/
/******************************************************************************/
