/* 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 ) Source file for tests shared among several benchmarks */ /******************************************************************************/ template inline bool tolerance_equal(T &a, T &b) { T diff = a - b; return (abs(diff) < 1.0e-6); } template<> inline bool tolerance_equal(int32_t &a, int32_t &b) { return (a == b); } template<> inline bool tolerance_equal(uint32_t &a, uint32_t &b) { return (a == b); } template<> inline bool tolerance_equal(uint64_t &a, uint64_t &b) { return (a == b); } template<> inline bool tolerance_equal(int64_t &a, int64_t &b) { return (a == b); } template<> inline bool tolerance_equal(double &a, double &b) { double diff = a - b; double reldiff = diff; if (fabs(a) > 1.0e-8) reldiff = diff / a; return (fabs(reldiff) < 1.0e-6); } template<> inline bool tolerance_equal(float &a, float &b) { float diff = a - b; double reldiff = diff; if (fabs(a) > 1.0e-4) reldiff = diff / a; return (fabs(reldiff) < 1.0e-3); // single precision divide test is really imprecise } /******************************************************************************/ template inline void check_shifted_sum(T result) { T temp = (T)SIZE * Shifter::do_shift((T)init_value); if (!tolerance_equal(result,temp)) printf("test %i failed\n", current_test); } template inline void check_shifted_sum_CSE(T result) { T temp = (T)0.0; if (!tolerance_equal(result,temp)) printf("test %i failed\n", current_test); } template inline void check_shifted_variable_sum(T result, T var) { T temp = (T)SIZE * Shifter::do_shift((T)init_value, var); if (!tolerance_equal(result,temp)) printf("test %i failed\n", current_test); } template inline void check_shifted_variable_sum(T result, T var1, T var2, T var3, T var4) { T temp = (T)SIZE * Shifter::do_shift((T)init_value, var1, var2, var3, var4); if (!tolerance_equal(result,temp)) printf("test %i failed\n", current_test); } template inline void check_shifted_variable_sum_CSE(T result, T var) { T temp = (T)0.0; if (!tolerance_equal(result,temp)) printf("test %i failed\n", current_test); } template inline void check_shifted_variable_sum_CSE(T result, T var1, T var2, T var3, T var4) { T temp = (T)0.0; if (!tolerance_equal(result,temp)) printf("test %i failed\n", current_test); } /******************************************************************************/ template void fill(Iterator first, Iterator last, T value) { while (first != last) *first++ = value; } /******************************************************************************/ template struct custom_constant_add { static T do_shift(T input) { return (input + T(10)); } }; /******************************************************************************/ template struct custom_multiple_constant_add { static T do_shift(T input) { return (input + T(1) + T(2) + T(3) + T(4)); } }; /******************************************************************************/ template struct custom_constant_sub { static T do_shift(T input) { return (input - T(10)); } }; /******************************************************************************/ template struct custom_multiple_constant_sub { static T do_shift(T input) { return (input - T(1) - T(2) - T(3) - T(4)); } }; /******************************************************************************/ template struct custom_constant_multiply { static T do_shift(T input) { return (input * T(120)); } }; /******************************************************************************/ // this should result in a single multiply template struct custom_multiple_constant_multiply { static T do_shift(T input) { return (input * T(2) * T(3) * T(4) * T(5)); } }; /******************************************************************************/ // this should result in a single add template struct custom_multiple_constant_multiply2 { static T do_shift(T input) { return (input + T(2) * T(3) * T(4) * T(5)); } }; /******************************************************************************/ template struct custom_constant_divide { static T do_shift(T input) { return (input / T(5)); } }; /******************************************************************************/ template struct custom_multiple_constant_divide { static T do_shift(T input) { return ((((input / T(2) ) / T(3) ) / T(4)) / T(5)); } }; /******************************************************************************/ // this more likely to have constants fused than the version above template struct custom_multiple_constant_divide2 { static T do_shift(T input) { return (input + (((T(120) / T(3) ) / T(4)) / T(5))); } }; /******************************************************************************/ template struct custom_multiple_constant_mixed { static T do_shift(T input) { return (input + T(2) - T(3) * T(4) / T(5)); } }; /******************************************************************************/ template struct custom_constant_and { static T do_shift(T input) { return (input & T(10)); } }; /******************************************************************************/ template struct custom_multiple_constant_and { static T do_shift(T input) { return (input & T(15) & T(30) & T(31) & T(63)); } }; /******************************************************************************/ template struct custom_constant_or { static T do_shift(T input) { return (input | T(10)); } }; /******************************************************************************/ template struct custom_multiple_constant_or { static T do_shift(T input) { return (input | T(15) | T(30) | T(31) | T(63)); } }; /******************************************************************************/ template struct custom_constant_xor { static T do_shift(T input) { return (input ^ T(10)); } }; /******************************************************************************/ template struct custom_multiple_constant_xor { static T do_shift(T input) { return (input ^ T(15) ^ T(30) ^ T(31) ^ T(63)); } }; /******************************************************************************/ template struct custom_two { static T do_shift(T input) { return (T(2)); } }; /******************************************************************************/ template struct custom_add_constants { static T do_shift(T input) { return (T(1) + T(2)); } }; /******************************************************************************/ template struct custom_sub_constants { static T do_shift(T input) { return (T(2) - T(1)); } }; /******************************************************************************/ template struct custom_multiply_constants { static T do_shift(T input) { return (T(2) * T(3)); } }; /******************************************************************************/ template struct custom_divide_constants { static T do_shift(T input) { return (T(20) / T(10)); } }; /******************************************************************************/ template struct custom_mod_constants { static T do_shift(T input) { return (T(23) % T(10)); } }; /******************************************************************************/ template struct custom_and_constants { static T do_shift(T input) { return (T(23) & T(10)); } }; /******************************************************************************/ template struct custom_or_constants { static T do_shift(T input) { return (T(23) | T(10)); } }; /******************************************************************************/ template struct custom_xor_constants { static T do_shift(T input) { return (T(23) ^ T(10)); } }; /******************************************************************************/ template struct custom_equal_constants { static T do_shift(T input) { return (T(23) == T(10)); } }; /******************************************************************************/ template struct custom_notequal_constants { static T do_shift(T input) { return (T(23) != T(10)); } }; /******************************************************************************/ template struct custom_greaterthan_constants { static T do_shift(T input) { return (T(23) > T(10)); } }; /******************************************************************************/ template struct custom_lessthan_constants { static T do_shift(T input) { return (T(23) < T(10)); } }; /******************************************************************************/ template struct custom_greaterthanequal_constants { static T do_shift(T input) { return (T(23) >= T(10)); } }; /******************************************************************************/ template struct custom_lessthanequal_constants { static T do_shift(T input) { return (T(23) <= T(10)); } }; /******************************************************************************/ template struct custom_add_variable { static T do_shift(T input, T v1) { return (input + v1); } }; /******************************************************************************/ template struct custom_sub_variable { static T do_shift(T input, T v1) { return (input - v1); } }; /******************************************************************************/ template struct custom_multiply_variable { static T do_shift(T input, T v1) { return (input * v1); } }; /******************************************************************************/ template struct custom_divide_variable { static T do_shift(T input, T v1) { return (input / v1); } }; /******************************************************************************/ template struct custom_add_multiple_variable { static T do_shift(T input, T v1, T v2, T v3, T v4) { return (input + v1 + v2 + v3 + v4); } }; /******************************************************************************/ template struct custom_sub_multiple_variable { static T do_shift(T input, T v1, T v2, T v3, T v4) { return (input - v1 - v2 - v3 - v4); } }; /******************************************************************************/ template struct custom_multiply_multiple_variable { static T do_shift(T input, T v1, T v2, T v3, T v4) { return (input * v1 * v2 * v3 * v4); } }; /******************************************************************************/ // something more likely to be moved out of loops, and a sanity check template struct custom_multiply_multiple_variable2 { static T do_shift(T input, T v1, T v2, T v3, T v4) { return (input + v1 * v2 * v3 * v4); } }; /******************************************************************************/ // this can NOT have CSE and loop invariant motion applied in integer math // and can only be optimized in float if inexact math is allowed template struct custom_divide_multiple_variable { static T do_shift(T input, T v1, T v2, T v3, T v4) { return ((((input / v1 ) / v2 ) / v3) / v4); } }; /******************************************************************************/ // this can have CSE and loop invariant motion applied in integer math // this should be optimizeable without inexact math template struct custom_divide_multiple_variable2 { static T do_shift(T input, T v1, T v2, T v3, T v4) { return (input + (((v1 / v2 ) / v3) / v4)); } }; /******************************************************************************/ template struct custom_mixed_multiple_variable { static T do_shift(T input, T v1, T v2, T v3, T v4) { return (input + v1 - v2 * v3 / v4); } }; /******************************************************************************/ template struct custom_variable_and { static T do_shift(T input, T v1) { return (input & v1); } }; /******************************************************************************/ template struct custom_multiple_variable_and { static T do_shift(T input, T v1, T v2, T v3, T v4) { return (input & v1 & v2 & v3 & v4); } }; /******************************************************************************/ template struct custom_variable_or { static T do_shift(T input, T v1) { return (input | v1); } }; /******************************************************************************/ template struct custom_multiple_variable_or { static T do_shift(T input, T v1, T v2, T v3, T v4) { return (input | v1 | v2 | v3 | v4); } }; /******************************************************************************/ template struct custom_variable_xor { static T do_shift(T input, T v1) { return (input ^ v1); } }; /******************************************************************************/ template struct custom_multiple_variable_xor { static T do_shift(T input, T v1, T v2, T v3, T v4) { return (input ^ v1 ^ v2 ^ v3 ^ v4); } }; /******************************************************************************/ template struct custom_identity { static T do_shift(T input) { return (input); } }; /******************************************************************************/ template struct custom_add_zero { static T do_shift(T input) { return (input + T(0)); } }; /******************************************************************************/ template struct custom_sub_zero { static T do_shift(T input) { return (input - T(0)); } }; /******************************************************************************/ template struct custom_negate { static T do_shift(T input) { return (-input); } }; /******************************************************************************/ template struct custom_negate_twice { static T do_shift(T input) { return (-(-input)); } }; /******************************************************************************/ template struct custom_zero_minus { static T do_shift(T input) { return (T(0) - input); } }; /******************************************************************************/ template struct custom_times_one { static T do_shift(T input) { return (input * T(1)); } }; /******************************************************************************/ template struct custom_divideby_one { static T do_shift(T input) { return (input / T(1)); } }; /******************************************************************************/ template struct custom_algebra_mixed { static T do_shift(T input) { return (-(T(0) - (((input + T(0)) - T(0)) / T(1)))) * T(1); } }; /******************************************************************************/ template struct custom_zero { static T do_shift(T input) { return T(0); } }; /******************************************************************************/ template struct custom_times_zero { static T do_shift(T input) { return (input * T(0)); } }; /******************************************************************************/ template struct custom_subtract_self { static T do_shift(T input) { return (input - input); } }; /******************************************************************************/ template struct custom_algebra_mixed_constant { static T do_shift(T input) { return (input - (-(T(0) - (((input + T(0)) / T(1)) - T(0)))) * T(1)); } }; /******************************************************************************/ template struct custom_cse1 { static T do_shift(T v1, T v2, T v3) { return (v1 * (v2 - v3) ); } }; /******************************************************************************/ template struct custom_and_self { static T do_shift(T input) { return (input & input); } }; /******************************************************************************/ template struct custom_or_self { static T do_shift(T input) { return (input | input); } }; /******************************************************************************/ template struct custom_xor_self { static T do_shift(T input) { return (input ^ input); } }; /******************************************************************************/ template struct custom_or_zero { static T do_shift(T input) { return (input | T(0)); } }; /******************************************************************************/ template struct custom_xor_zero { static T do_shift(T input) { return (input ^ T(0)); } }; /******************************************************************************/ template struct custom_andnot_zero { static T do_shift(T input) { return (input & ~ T(0)); } }; /******************************************************************************/ template struct custom_and_zero { static T do_shift(T input) { return (input & T(0)); } }; /******************************************************************************/ template struct custom_mod_one { static T do_shift(T input) { return (input % T(1)); } }; /******************************************************************************/ template struct custom_equal_self { static T do_shift(T input) { return (input == input); } }; /******************************************************************************/ template struct custom_notequal_self { static T do_shift(T input) { return (input != input); } }; /******************************************************************************/ template struct custom_greaterthan_self { static T do_shift(T input) { return (input > input); } }; /******************************************************************************/ template struct custom_lessthan_self { static T do_shift(T input) { return (input < input); } }; /******************************************************************************/ template struct custom_greaterthanequal_self { static T do_shift(T input) { return (input >= input); } }; /******************************************************************************/ template struct custom_lessthanequal_self { static T do_shift(T input) { return (input <= input); } }; /******************************************************************************/ template void test_constant(T* first, int count, const char *label) { int i; start_timer(); for(i = 0; i < iterations; ++i) { T result = 0; for (int n = 0; n < count; ++n) { result += Shifter::do_shift( first[n] ); } check_shifted_sum(result); } record_result( timer(), label ); } /******************************************************************************/ template void test_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 += Shifter::do_shift( first[n], v1 ); } check_shifted_variable_sum(result, v1); } record_result( timer(), label ); } /******************************************************************************/ template void test_variable4(T* first, int count, T v1, T v2, T v3, T v4, const char *label) { int i; start_timer(); for(i = 0; i < iterations; ++i) { T result = 0; for (int n = 0; n < count; ++n) { result += Shifter::do_shift( first[n], v1, v2, v3, v4 ); } check_shifted_variable_sum(result, v1, v2, v3, v4); } record_result( timer(), label ); } /******************************************************************************/ template void test_CSE_opt(T* first, int count, T v1, const char *label) { int i; start_timer(); for(i = 0; i < iterations; ++i) { T result = 0; T temp = Shifter::do_shift( v1, first[0], first[1] ); temp += temp; result += first[0] + temp; result -= first[1] + temp; for (int n = 1; n < count; ++n) { temp = Shifter::do_shift( v1, first[n-1], first[n] ); temp += temp; result += first[n-1] + temp; result -= first[n] + temp; } check_shifted_variable_sum_CSE(result, v1); } record_result( timer(), label ); } /******************************************************************************/ template void test_CSE(T* first, int count, T v1, const char *label) { int i; start_timer(); for(i = 0; i < iterations; ++i) { T result = 0; result += first[0] + Shifter::do_shift( v1, first[0], first[1] ) + Shifter::do_shift( v1, first[0], first[1] ); result -= first[1] + Shifter::do_shift( v1, first[0], first[1] ) + Shifter::do_shift( v1, first[0], first[1] ); for (int n = 1; n < count; ++n) { result += first[n-1] + Shifter::do_shift( v1, first[n-1], first[n] ) + Shifter::do_shift( v1, first[n-1], first[n] ); result -= first[n] + Shifter::do_shift( v1, first[n-1], first[n] ) + Shifter::do_shift( v1, first[n-1], first[n] ); } check_shifted_variable_sum_CSE(result, v1); } record_result( timer(), label ); } /******************************************************************************/