| 1 | // RUN: %libomp-cxx-compile -fopenmp-version=60 && %libomp-run |
| 2 | #include <stdio.h> |
| 3 | #include <omp.h> |
| 4 | #include <limits.h> |
| 5 | #include <complex.h> |
| 6 | #include <math.h> |
| 7 | #include "omp_testsuite.h" |
| 8 | |
| 9 | #define N 10 |
| 10 | class Sum { |
| 11 | int val; |
| 12 | |
| 13 | public: |
| 14 | Sum(int v = 0) : val(v) {} |
| 15 | Sum operator+(const Sum &rhs) const { return Sum(val + rhs.val); } |
| 16 | Sum &operator+=(const Sum &rhs) { |
| 17 | val += rhs.val; |
| 18 | return *this; |
| 19 | } |
| 20 | int getValue() const { return val; } |
| 21 | }; |
| 22 | |
| 23 | // Declare OpenMP reduction |
| 24 | #pragma omp declare reduction(sum_reduction:Sum : omp_out += omp_in) \ |
| 25 | initializer(omp_priv = Sum(0)) |
| 26 | |
| 27 | #pragma omp declare reduction(sum_pctor_reduction:Sum : omp_out += omp_in) \ |
| 28 | initializer(omp_priv = Sum(1)) // non-default ctor |
| 29 | |
| 30 | int checkUserDefinedReduction() { |
| 31 | Sum final_result_udr(0); |
| 32 | Sum final_result_udr_pctor(1); |
| 33 | Sum array_sum[N]; |
| 34 | int error_flag = 0; |
| 35 | int expected_value = 0; |
| 36 | int expected_value_pctor = 0; |
| 37 | for (int i = 0; i < N; ++i) { |
| 38 | array_sum[i] = Sum(i); |
| 39 | expected_value += i; // Calculate expected sum: 0 + 1 + ... + (N-1) |
| 40 | expected_value_pctor += i; |
| 41 | } |
| 42 | int num_threads_for_pctor_calc = 4; // num_threads(4) |
| 43 | int priv_initializer_val_pctor = 1; // initializer(omp_priv = Sum(1)) |
| 44 | expected_value_pctor += |
| 45 | num_threads_for_pctor_calc + priv_initializer_val_pctor; |
| 46 | #pragma omp parallel num_threads(4) private(final_result_udr) private( \ |
| 47 | final_result_udr_pctor) |
| 48 | { |
| 49 | #pragma omp for reduction(sum_reduction : final_result_udr) \ |
| 50 | reduction(sum_pctor_reduction : final_result_udr_pctor) |
| 51 | for (int i = 0; i < N; ++i) { |
| 52 | final_result_udr += array_sum[i]; |
| 53 | final_result_udr_pctor += array_sum[i]; |
| 54 | } |
| 55 | |
| 56 | if (final_result_udr.getValue() != expected_value || |
| 57 | final_result_udr_pctor.getValue() != expected_value_pctor) |
| 58 | error_flag += 1; |
| 59 | } |
| 60 | return error_flag; |
| 61 | } |
| 62 | void performMinMaxRed(int &min_val, int &max_val) { |
| 63 | int input_data[] = {7, 3, 12, 5, 8}; |
| 64 | int n_size = sizeof(input_data) / sizeof(input_data[0]); |
| 65 | min_val = INT_MAX; |
| 66 | max_val = INT_MIN; |
| 67 | #pragma omp for reduction(original(private), min : min_val) \ |
| 68 | reduction(original(private), max : max_val) |
| 69 | for (int i = 0; i < n_size; ++i) { |
| 70 | if (input_data[i] < min_val) |
| 71 | min_val = input_data[i]; |
| 72 | if (input_data[i] > max_val) |
| 73 | max_val = input_data[i]; |
| 74 | } |
| 75 | } |
| 76 | std::complex<double> doComplexReduction(std::complex<double> *arr) { |
| 77 | std::complex<double> result(1, 0); |
| 78 | |
| 79 | #pragma omp declare reduction(* : std::complex<double> : omp_out *= omp_in) \ |
| 80 | initializer(omp_priv = std::complex<double>(1, 0)) |
| 81 | |
| 82 | #pragma omp for reduction(original(private), * : result) |
| 83 | for (int i = 0; i < N; ++i) |
| 84 | result *= arr[i]; |
| 85 | |
| 86 | return result; |
| 87 | } |
| 88 | |
| 89 | void performReductions(int n_elements, const int *input_values, |
| 90 | int &sum_val_out, int &prod_val_out, |
| 91 | float &float_sum_val_out) { |
| 92 | // private variables for this thread's reduction. |
| 93 | sum_val_out = 0; |
| 94 | prod_val_out = 1; |
| 95 | float_sum_val_out = 0.0f; |
| 96 | |
| 97 | const float kPiValue = 3.14f; |
| 98 | #pragma omp for reduction(original(private), + : sum_val_out) \ |
| 99 | reduction(original(private), * : prod_val_out) \ |
| 100 | reduction(original(private), + : float_sum_val_out) |
| 101 | for (int i = 0; i < n_elements; ++i) { |
| 102 | sum_val_out += input_values[i]; |
| 103 | prod_val_out *= (i + 1); |
| 104 | float_sum_val_out += kPiValue; |
| 105 | } |
| 106 | } |
| 107 | int main(void) { |
| 108 | int input_array[N]; |
| 109 | int total_errors = 0; |
| 110 | const float kPiVal = 3.14f; |
| 111 | const int kExpectedSum = 45; // Sum of 0..9 |
| 112 | const int kExpectedProd = 3628800; // 10! |
| 113 | const float kExpectedFsum = 31.400000f; // 3.14f * 10 |
| 114 | const float kTolerance = 1e-4f; |
| 115 | const int kExpectedMin = 3; |
| 116 | const int kExpectedMax = 12; |
| 117 | std::complex<double> arr[N]; |
| 118 | std::complex<double> kExpectedComplex(1, 0); |
| 119 | // Initialize the array |
| 120 | for (int i = 1; i <= N; ++i) { |
| 121 | arr[i - 1] = std::complex<double>( |
| 122 | 1.0 + 0.1 * i, 0.5 * i); // Avoid zero to prevent multiplication by zero |
| 123 | kExpectedComplex *= arr[i - 1]; |
| 124 | } |
| 125 | |
| 126 | for (int i = 0; i < N; i++) |
| 127 | input_array[i] = i; |
| 128 | #pragma omp parallel num_threads(4) |
| 129 | { |
| 130 | |
| 131 | int t_sum_v; |
| 132 | int t_prod_v; |
| 133 | float t_fsum_v; |
| 134 | performReductions(N, input_values: input_array, sum_val_out&: t_sum_v, prod_val_out&: t_prod_v, float_sum_val_out&: t_fsum_v); |
| 135 | if (t_sum_v != kExpectedSum) |
| 136 | total_errors++; |
| 137 | if (t_prod_v != kExpectedProd) |
| 138 | total_errors++; |
| 139 | if (std::abs(x: t_fsum_v - kExpectedFsum) > kTolerance) |
| 140 | total_errors++; |
| 141 | } |
| 142 | #pragma omp parallel num_threads(4) |
| 143 | { |
| 144 | int t_min_v; |
| 145 | int t_max_v; |
| 146 | performMinMaxRed(min_val&: t_min_v, max_val&: t_max_v); |
| 147 | if (t_min_v != kExpectedMin) |
| 148 | total_errors++; |
| 149 | if (t_max_v != kExpectedMax) |
| 150 | total_errors++; |
| 151 | } |
| 152 | total_errors += checkUserDefinedReduction(); |
| 153 | #pragma omp parallel num_threads(4) |
| 154 | { |
| 155 | std::complex<double> result(1, 0); |
| 156 | result = doComplexReduction(arr); |
| 157 | if (std::abs(x: result.real() - kExpectedComplex.real()) > 1e-6 || |
| 158 | std::abs(x: result.imag() - kExpectedComplex.imag()) > 1e-6) { |
| 159 | total_errors++; |
| 160 | } |
| 161 | } |
| 162 | if (total_errors != 0) |
| 163 | fprintf(stderr, format: "ERROR: reduction on private variable %d\n" , total_errors); |
| 164 | |
| 165 | return total_errors; |
| 166 | } |
| 167 | |