]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
OpenMP: Support complex/float in && and || reduction
authorTobias Burnus <tobias@codesourcery.com>
Fri, 14 May 2021 07:30:01 +0000 (09:30 +0200)
committerTobias Burnus <tobias@codesourcery.com>
Fri, 14 May 2021 08:01:27 +0000 (10:01 +0200)
C/C++ permit logical AND and logical OR also with floating-point or complex
arguments by doing an unequal zero comparison; the result is an 'int' with
value one or zero.  Hence, those are also permitted as reduction variable,
even though it is not the most sensible thing to do.

gcc/c/ChangeLog:

* c-typeck.c (c_finish_omp_clauses): Accept float + complex
for || and && reductions.

gcc/cp/ChangeLog:

* semantics.c (finish_omp_reduction_clause): Accept float + complex
for || and && reductions.

gcc/ChangeLog:

* omp-low.c (lower_rec_input_clauses, lower_reduction_clauses): Handle
&& and || with floating-point and complex arguments.

gcc/testsuite/ChangeLog:

* gcc.dg/gomp/clause-1.c: Use 'reduction(&:..)' instead of '...(&&:..)'.

libgomp/ChangeLog:

* testsuite/libgomp.c-c++-common/reduction-1.c: New test.
* testsuite/libgomp.c-c++-common/reduction-2.c: New test.
* testsuite/libgomp.c-c++-common/reduction-3.c: New test.

(cherry picked from commit 1580fc764423bf89e9b853aaa8c65999e37ccb8b)

13 files changed:
gcc/ChangeLog.omp
gcc/c/ChangeLog.omp
gcc/c/c-typeck.c
gcc/cp/ChangeLog.omp
gcc/cp/semantics.c
gcc/omp-low.c
gcc/testsuite/ChangeLog.omp
gcc/testsuite/gcc.dg/gomp/clause-1.c
libgomp/ChangeLog.omp
libgomp/testsuite/libgomp.c-c++-common/reduction-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/reduction-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/reduction-3.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/reduction-4.c [new file with mode: 0644]

index 8e306a704801748a62237880c0efa8b5e149029d..76f1f4a79d3588e44733582c8be953c58ab5622d 100644 (file)
@@ -1,3 +1,11 @@
+2021-05-14  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-05-04  Tobias Burnus  <tobias@codesourcery.com>
+
+       * omp-low.c (lower_rec_input_clauses, lower_reduction_clauses): Handle
+       && and || with floating-point and complex arguments.
+
 2021-05-14  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
index 0f6ac422f3121fc7944b2378c68f405ebc174a42..ed366d518c475effd4e11dad81049ef9ce475883 100644 (file)
@@ -1,3 +1,11 @@
+2021-05-14  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-05-04  Tobias Burnus  <tobias@codesourcery.com>
+
+       * c-typeck.c (c_finish_omp_clauses): Accept float + complex
+       for || and && reductions.
+
 2020-08-19  Sandra Loosemore  <sandra@codesourcery.com>
 
        Add a "combined" flag for "acc kernels loop" etc directives.
index d71d69c5b7f5ea85854ec0271b7cf5fc8090e72d..e09f24ac5a48de2cacf0ef43a5531b3bffcd9906 100644 (file)
@@ -14144,6 +14144,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
                case PLUS_EXPR:
                case MULT_EXPR:
                case MINUS_EXPR:
+               case TRUTH_ANDIF_EXPR:
+               case TRUTH_ORIF_EXPR:
                  break;
                case MIN_EXPR:
                  if (TREE_CODE (type) == COMPLEX_TYPE)
@@ -14162,14 +14164,6 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
                case BIT_IOR_EXPR:
                  r_name = "|";
                  break;
-               case TRUTH_ANDIF_EXPR:
-                 if (FLOAT_TYPE_P (type))
-                   r_name = "&&";
-                 break;
-               case TRUTH_ORIF_EXPR:
-                 if (FLOAT_TYPE_P (type))
-                   r_name = "||";
-                 break;
                default:
                  gcc_unreachable ();
                }
index 070f5633308c4a4090cff6e9f2da36bdb9f901f7..8e6fa988467826373f42b70f2e8af8252c936a00 100644 (file)
@@ -1,3 +1,11 @@
+2021-05-14  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-05-04  Tobias Burnus  <tobias@codesourcery.com>
+
+       * semantics.c (finish_omp_reduction_clause): Accept float + complex
+       for || and && reductions.
+
 2020-08-19  Sandra Loosemore  <sandra@codesourcery.com>
 
        Add a "combined" flag for "acc kernels loop" etc directives.
        (finish_function): Call c_oacc_annotate_loops_in_kernels_regions.
 
 2018-12-13  Cesar Philippidis  <cesar@codesourcery.com>
-            Nathan Sidwell  <nathan@acm.org>
-            Julian Brown  <julian@codesourcery.com>
+           Nathan Sidwell  <nathan@acm.org>
+           Julian Brown  <julian@codesourcery.com>
 
-        * parser.c (cp_parser_omp_var_list_no_open):  New c_omp_region_type
-        argument.  Use it to specialize handling of OMP_CLAUSE_REDUCTION for
-        OpenACC.
+       * parser.c (cp_parser_omp_var_list_no_open):  New c_omp_region_type
+       argument.  Use it to specialize handling of OMP_CLAUSE_REDUCTION for
+       OpenACC.
        (cp_parser_omp_var_list): Add c_omp_region_type argument. Update call
        to cp_parser_omp_var_list_parens.
        (cp_parser_oacc_data_clause): Update call to cp_parser_omp_var_list.
-        (cp_parser_omp_clause_reduction): Change is_omp boolean parameter to
-        c_omp_region_type.  Update call to cp_parser_omp_var_list_no_open.
-        (cp_parser_oacc_all_clauses): Update call to
-        cp_parser_omp_clause_reduction.
-        (cp_parser_omp_all_clauses): Likewise.
-        * semantics.c (finish_omp_reduction_clause): Add c_omp_region_type
+       (cp_parser_omp_clause_reduction): Change is_omp boolean parameter to
+       c_omp_region_type.  Update call to cp_parser_omp_var_list_no_open.
+       (cp_parser_oacc_all_clauses): Update call to
+       cp_parser_omp_clause_reduction.
+       (cp_parser_omp_all_clauses): Likewise.
+       * semantics.c (finish_omp_reduction_clause): Add c_omp_region_type
        argument.  Suppress user-defined reduction error for OpenACC.
        (finish_omp_clauses): Emit an error on orphan OpenACC gang reductions.
 
index 2ef838df37bbb0c6296e75ec18707006913e3708..5a159d30165540a4df28717059681ba7265df71c 100644 (file)
@@ -6091,6 +6091,8 @@ finish_omp_reduction_clause (tree c, enum c_omp_region_type ort,
       case PLUS_EXPR:
       case MULT_EXPR:
       case MINUS_EXPR:
+      case TRUTH_ANDIF_EXPR:
+      case TRUTH_ORIF_EXPR:
        predefined = true;
        break;
       case MIN_EXPR:
@@ -6106,12 +6108,6 @@ finish_omp_reduction_clause (tree c, enum c_omp_region_type ort,
          break;
        predefined = true;
        break;
-      case TRUTH_ANDIF_EXPR:
-      case TRUTH_ORIF_EXPR:
-       if (FLOAT_TYPE_P (type))
-         break;
-       predefined = true;
-       break;
       default:
        break;
       }
index 5eb8aee9c5e68c86d338619e512563642fa2860b..d50a433d4c1e4176e48d165e31031ec830df5b82 100644 (file)
@@ -6714,6 +6714,11 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                  if (code == MINUS_EXPR)
                    code = PLUS_EXPR;
 
+                 /* C/C++ permits FP/complex with || and &&.  */
+                 bool is_fp_and_or
+                   = ((code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
+                      && (FLOAT_TYPE_P (TREE_TYPE (new_var))
+                          || TREE_CODE (TREE_TYPE (new_var)) == COMPLEX_TYPE));
                  tree new_vard = new_var;
                  if (is_simd && omp_is_reference (var))
                    {
@@ -6762,7 +6767,20 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                          x = build2 (code, TREE_TYPE (ivar), ivar, x);
                          gimplify_assign (ivar, x, &llist[2]);
                        }
-                     x = build2 (code, TREE_TYPE (ref), ref, ivar);
+                     tree ivar2 = ivar;
+                     tree ref2 = ref;
+                     if (is_fp_and_or)
+                       {
+                         tree zero = build_zero_cst (TREE_TYPE (ivar));
+                         ivar2 = fold_build2_loc (clause_loc, NE_EXPR,
+                                                  integer_type_node, ivar,
+                                                  zero);
+                         ref2 = fold_build2_loc (clause_loc, NE_EXPR,
+                                                 integer_type_node, ref, zero);
+                       }
+                     x = build2 (code, TREE_TYPE (ref), ref2, ivar2);
+                     if (is_fp_and_or)
+                       x = fold_convert (TREE_TYPE (ref), x);
                      ref = build_outer_var_ref (var, ctx);
                      gimplify_assign (ref, x, &llist[1]);
 
@@ -6781,8 +6799,22 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                      if (is_simd)
                        {
                          tree ref = build_outer_var_ref (var, ctx);
-
-                         x = build2 (code, TREE_TYPE (ref), ref, new_var);
+                         tree new_var2 = new_var;
+                         tree ref2 = ref;
+                         if (is_fp_and_or)
+                           {
+                             tree zero = build_zero_cst (TREE_TYPE (new_var));
+                             new_var2
+                               = fold_build2_loc (clause_loc, NE_EXPR,
+                                                  integer_type_node, new_var,
+                                                  zero);
+                             ref2 = fold_build2_loc (clause_loc, NE_EXPR,
+                                                     integer_type_node, ref,
+                                                     zero);
+                           }
+                         x = build2 (code, TREE_TYPE (ref2), ref2, new_var2);
+                         if (is_fp_and_or)
+                           x = fold_convert (TREE_TYPE (new_var), x);
                          ref = build_outer_var_ref (var, ctx);
                          gimplify_assign (ref, x, dlist);
                        }
@@ -7736,13 +7768,32 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp,
       if (code == MINUS_EXPR)
         code = PLUS_EXPR;
 
+      /* C/C++ permits FP/complex with || and &&.  */
+      bool is_fp_and_or = ((code == TRUTH_ANDIF_EXPR
+                           || code == TRUTH_ORIF_EXPR)
+                          && (FLOAT_TYPE_P (TREE_TYPE (new_var))
+                              || (TREE_CODE (TREE_TYPE (new_var))
+                                  == COMPLEX_TYPE)));
       if (count == 1)
        {
          tree addr = build_fold_addr_expr_loc (clause_loc, ref);
 
          addr = save_expr (addr);
          ref = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (addr)), addr);
-         x = fold_build2_loc (clause_loc, code, TREE_TYPE (ref), ref, new_var);
+         tree new_var2 = new_var;
+         tree ref2 = ref;
+         if (is_fp_and_or)
+           {
+             tree zero = build_zero_cst (TREE_TYPE (new_var));
+             new_var2 = fold_build2_loc (clause_loc, NE_EXPR,
+                                         integer_type_node, new_var, zero);
+             ref2 = fold_build2_loc (clause_loc, NE_EXPR, integer_type_node,
+                                     ref, zero);
+           }
+         x = fold_build2_loc (clause_loc, code, TREE_TYPE (new_var2), ref2,
+                              new_var2);
+         if (is_fp_and_or)
+           x = fold_convert (TREE_TYPE (new_var), x);
          x = build2 (OMP_ATOMIC, void_type_node, addr, x);
          OMP_ATOMIC_MEMORY_ORDER (x) = OMP_MEMORY_ORDER_RELAXED;
          gimplify_and_add (x, stmt_seqp);
@@ -7847,7 +7898,19 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp,
            }
          else
            {
-             x = build2 (code, TREE_TYPE (out), out, priv);
+             tree out2 = out;
+             tree priv2 = priv;
+             if (is_fp_and_or)
+               {
+                 tree zero = build_zero_cst (TREE_TYPE (out));
+                 out2 = fold_build2_loc (clause_loc, NE_EXPR,
+                                         integer_type_node, out, zero);
+                 priv2 = fold_build2_loc (clause_loc, NE_EXPR,
+                                          integer_type_node, priv, zero);
+               }
+             x = build2 (code, TREE_TYPE (out2), out2, priv2);
+             if (is_fp_and_or)
+               x = fold_convert (TREE_TYPE (out), x);
              out = unshare_expr (out);
              gimplify_assign (out, x, &sub_seq);
            }
@@ -7881,7 +7944,19 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp,
        }
       else
        {
-         x = build2 (code, TREE_TYPE (ref), ref, new_var);
+         tree new_var2 = new_var;
+         tree ref2 = ref;
+         if (is_fp_and_or)
+           {
+             tree zero = build_zero_cst (TREE_TYPE (new_var));
+             new_var2 = fold_build2_loc (clause_loc, NE_EXPR,
+                                         integer_type_node, new_var, zero);
+             ref2 = fold_build2_loc (clause_loc, NE_EXPR, integer_type_node,
+                                     ref, zero);
+           }
+         x = build2 (code, TREE_TYPE (ref), ref2, new_var2);
+         if (is_fp_and_or)
+           x = fold_convert (TREE_TYPE (new_var), x);
          ref = build_outer_var_ref (var, ctx);
          gimplify_assign (ref, x, &sub_seq);
        }
index b3c96619e4428e1646bf07cb42d04b14038868c6..d4a89ce34f887e7e8a463d2d7532b1c49cdcd8ec 100644 (file)
@@ -1,3 +1,10 @@
+2021-05-14  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-05-04  Tobias Burnus  <tobias@codesourcery.com>
+
+       * gcc.dg/gomp/clause-1.c: Use 'reduction(&:..)' instead of '...(&&:..)'.
+
 2021-05-07  Thomas Schwinge  <thomas@codesourcery.com>
 
        * c-c++-common/goacc/firstprivate-mappings-1.c: Fix up for C,
index 9d34b04160698c5071b0186de3f780023045c0c4..8e7cc950d22a939407c03db3c404914fdeacd242 100644 (file)
@@ -56,7 +56,7 @@ foo (int x)
     ;
 #pragma omp p reduction (|:d) /* { dg-error "has invalid type for" } */
     ;
-#pragma omp p reduction (&&:d) /* { dg-error "has invalid type for" } */
+#pragma omp p reduction (&:d) /* { dg-error "has invalid type for" } */
     ;
 #pragma omp p copyin (d) /* { dg-error "must be 'threadprivate'" } */
     ;
index e0f1ec0b50c2874c3deb8e15c7dcfce766d89826..1b4a2e35012969e0f05c01089e849a730058416f 100644 (file)
@@ -1,3 +1,12 @@
+2021-05-14  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-05-04  Tobias Burnus  <tobias@codesourcery.com>
+
+       * testsuite/libgomp.c-c++-common/reduction-1.c: New test.
+       * testsuite/libgomp.c-c++-common/reduction-2.c: New test.
+       * testsuite/libgomp.c-c++-common/reduction-3.c: New test.
+
 2021-05-14  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
diff --git a/libgomp/testsuite/libgomp.c-c++-common/reduction-1.c b/libgomp/testsuite/libgomp.c-c++-common/reduction-1.c
new file mode 100644 (file)
index 0000000..89a4153
--- /dev/null
@@ -0,0 +1,192 @@
+/* C / C++'s logical AND and OR operators take any scalar argument
+   which compares (un)equal to 0 - the result 1 or 0 and of type int.
+
+   In this testcase, the int result is again converted to a floating-poing
+   or complex type.
+
+   While having a floating-point/complex array element with || and && can make
+   sense, having a non-integer/non-bool reduction variable is odd but valid.
+
+   Test: FP reduction variable + FP array.  */
+
+#define N 1024
+_Complex float rcf[N];
+_Complex double rcd[N];
+float rf[N];
+double rd[N];
+
+int
+reduction_or ()
+{
+  float orf = 0;
+  double ord = 0;
+  _Complex float orfc = 0;
+  _Complex double ordc = 0;
+
+  #pragma omp parallel reduction(||: orf)
+  for (int i=0; i < N; ++i)
+    orf = orf || rf[i];
+
+  #pragma omp parallel for reduction(||: ord)
+  for (int i=0; i < N; ++i)
+    ord = ord || rcd[i];
+
+  #pragma omp parallel for simd reduction(||: orfc)
+  for (int i=0; i < N; ++i)
+    orfc = orfc || rcf[i];
+
+  #pragma omp parallel loop reduction(||: ordc)
+  for (int i=0; i < N; ++i)
+    ordc = ordc || rcd[i];
+
+  return orf + ord + __real__ orfc + __real__ ordc;
+}
+
+int
+reduction_or_teams ()
+{
+  float orf = 0;
+  double ord = 0;
+  _Complex float orfc = 0;
+  _Complex double ordc = 0;
+
+  #pragma omp teams distribute parallel for reduction(||: orf)
+  for (int i=0; i < N; ++i)
+    orf = orf || rf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(||: ord)
+  for (int i=0; i < N; ++i)
+    ord = ord || rcd[i];
+
+  #pragma omp teams distribute parallel for reduction(||: orfc)
+  for (int i=0; i < N; ++i)
+    orfc = orfc || rcf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(||: ordc)
+  for (int i=0; i < N; ++i)
+    ordc = ordc || rcd[i];
+
+  return orf + ord + __real__ orfc + __real__ ordc;
+}
+
+int
+reduction_and ()
+{
+  float andf = 1;
+  double andd = 1;
+  _Complex float andfc = 1;
+  _Complex double anddc = 1;
+
+  #pragma omp parallel reduction(&&: andf)
+  for (int i=0; i < N; ++i)
+    andf = andf && rf[i];
+
+  #pragma omp parallel for reduction(&&: andd)
+  for (int i=0; i < N; ++i)
+    andd = andd && rcd[i];
+
+  #pragma omp parallel for simd reduction(&&: andfc)
+  for (int i=0; i < N; ++i)
+    andfc = andfc && rcf[i];
+
+  #pragma omp parallel loop reduction(&&: anddc)
+  for (int i=0; i < N; ++i)
+    anddc = anddc && rcd[i];
+
+  return andf + andd + __real__ andfc + __real__ anddc;
+}
+
+int
+reduction_and_teams ()
+{
+  float andf = 1;
+  double andd = 1;
+  _Complex float andfc = 1;
+  _Complex double anddc = 1;
+
+  #pragma omp teams distribute parallel for reduction(&&: andf)
+  for (int i=0; i < N; ++i)
+    andf = andf && rf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(&&: andd)
+  for (int i=0; i < N; ++i)
+    andd = andd && rcd[i];
+
+  #pragma omp teams distribute parallel for reduction(&&: andfc)
+  for (int i=0; i < N; ++i)
+    andfc = andfc && rcf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(&&: anddc)
+  for (int i=0; i < N; ++i)
+    anddc = anddc && rcd[i];
+
+  return andf + andd + __real__ andfc + __real__ anddc;
+}
+
+int
+main ()
+{
+  for (int i = 0; i < N; ++i)
+    {
+      rf[i] = 0;
+      rd[i] = 0;
+      rcf[i] = 0;
+      rcd[i] = 0;
+    }
+
+  if (reduction_or () != 0)
+    __builtin_abort ();
+  if (reduction_or_teams () != 0)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  rf[10] = 1.0;
+  rd[15] = 1.0;
+  rcf[10] = 1.0;
+  rcd[15] = 1.0i;
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  for (int i = 0; i < N; ++i)
+    {
+      rf[i] = 1;
+      rd[i] = 1;
+      rcf[i] = 1;
+      rcd[i] = 1;
+    }
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 4)
+    __builtin_abort ();
+  if (reduction_and_teams () != 4)
+    __builtin_abort ();
+
+  rf[10] = 0.0;
+  rd[15] = 0.0;
+  rcf[10] = 0.0;
+  rcd[15] = 0.0;
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/reduction-2.c b/libgomp/testsuite/libgomp.c-c++-common/reduction-2.c
new file mode 100644 (file)
index 0000000..bdcba86
--- /dev/null
@@ -0,0 +1,192 @@
+/* C / C++'s logical AND and OR operators take any scalar argument
+   which compares (un)equal to 0 - the result 1 or 0 and of type int.
+
+   In this testcase, the int result is again converted to a floating-poing
+   or complex type.
+
+   While having a floating-point/complex array element with || and && can make
+   sense, having a non-integer/non-bool reduction variable is odd but valid.
+
+   Test: FP reduction variable + integer array.  */
+
+#define N 1024
+char rcf[N];
+short rcd[N];
+int rf[N];
+long rd[N];
+
+int
+reduction_or ()
+{
+  float orf = 0;
+  double ord = 0;
+  _Complex float orfc = 0;
+  _Complex double ordc = 0;
+
+  #pragma omp parallel reduction(||: orf)
+  for (int i=0; i < N; ++i)
+    orf = orf || rf[i];
+
+  #pragma omp parallel for reduction(||: ord)
+  for (int i=0; i < N; ++i)
+    ord = ord || rcd[i];
+
+  #pragma omp parallel for simd reduction(||: orfc)
+  for (int i=0; i < N; ++i)
+    orfc = orfc || rcf[i];
+
+  #pragma omp parallel loop reduction(||: ordc)
+  for (int i=0; i < N; ++i)
+    ordc = ordc || rcd[i];
+
+  return orf + ord + __real__ orfc + __real__ ordc;
+}
+
+int
+reduction_or_teams ()
+{
+  float orf = 0;
+  double ord = 0;
+  _Complex float orfc = 0;
+  _Complex double ordc = 0;
+
+  #pragma omp teams distribute parallel for reduction(||: orf)
+  for (int i=0; i < N; ++i)
+    orf = orf || rf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(||: ord)
+  for (int i=0; i < N; ++i)
+    ord = ord || rcd[i];
+
+  #pragma omp teams distribute parallel for reduction(||: orfc)
+  for (int i=0; i < N; ++i)
+    orfc = orfc || rcf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(||: ordc)
+  for (int i=0; i < N; ++i)
+    ordc = ordc || rcd[i];
+
+  return orf + ord + __real__ orfc + __real__ ordc;
+}
+
+int
+reduction_and ()
+{
+  float andf = 1;
+  double andd = 1;
+  _Complex float andfc = 1;
+  _Complex double anddc = 1;
+
+  #pragma omp parallel reduction(&&: andf)
+  for (int i=0; i < N; ++i)
+    andf = andf && rf[i];
+
+  #pragma omp parallel for reduction(&&: andd)
+  for (int i=0; i < N; ++i)
+    andd = andd && rcd[i];
+
+  #pragma omp parallel for simd reduction(&&: andfc)
+  for (int i=0; i < N; ++i)
+    andfc = andfc && rcf[i];
+
+  #pragma omp parallel loop reduction(&&: anddc)
+  for (int i=0; i < N; ++i)
+    anddc = anddc && rcd[i];
+
+  return andf + andd + __real__ andfc + __real__ anddc;
+}
+
+int
+reduction_and_teams ()
+{
+  float andf = 1;
+  double andd = 1;
+  _Complex float andfc = 1;
+  _Complex double anddc = 1;
+
+  #pragma omp teams distribute parallel for reduction(&&: andf)
+  for (int i=0; i < N; ++i)
+    andf = andf && rf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(&&: andd)
+  for (int i=0; i < N; ++i)
+    andd = andd && rcd[i];
+
+  #pragma omp teams distribute parallel for reduction(&&: andfc)
+  for (int i=0; i < N; ++i)
+    andfc = andfc && rcf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(&&: anddc)
+  for (int i=0; i < N; ++i)
+    anddc = anddc && rcd[i];
+
+  return andf + andd + __real__ andfc + __real__ anddc;
+}
+
+int
+main ()
+{
+  for (int i = 0; i < N; ++i)
+    {
+      rf[i] = 0;
+      rd[i] = 0;
+      rcf[i] = 0;
+      rcd[i] = 0;
+    }
+
+  if (reduction_or () != 0)
+    __builtin_abort ();
+  if (reduction_or_teams () != 0)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  rf[10] = 1;
+  rd[15] = 1;
+  rcf[10] = 1;
+  rcd[15] = 1;
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  for (int i = 0; i < N; ++i)
+    {
+      rf[i] = 1;
+      rd[i] = 1;
+      rcf[i] = 1;
+      rcd[i] = 1;
+    }
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 4)
+    __builtin_abort ();
+  if (reduction_and_teams () != 4)
+    __builtin_abort ();
+
+  rf[10] = 0;
+  rd[15] = 0;
+  rcf[10] = 0;
+  rcd[15] = 0;
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/reduction-3.c b/libgomp/testsuite/libgomp.c-c++-common/reduction-3.c
new file mode 100644 (file)
index 0000000..0f09aab
--- /dev/null
@@ -0,0 +1,192 @@
+/* C / C++'s logical AND and OR operators take any scalar argument
+   which compares (un)equal to 0 - the result 1 or 0 and of type int.
+
+   In this testcase, the int result is again converted to a floating-poing
+   or complex type.
+
+   While having a floating-point/complex array element with || and && can make
+   sense, having a non-integer/non-bool reduction variable is odd but valid.
+
+   Test: integer reduction variable + FP array.  */
+
+#define N 1024
+_Complex float rcf[N];
+_Complex double rcd[N];
+float rf[N];
+double rd[N];
+
+int
+reduction_or ()
+{
+  char orf = 0;
+  short ord = 0;
+  int orfc = 0;
+  long ordc = 0;
+
+  #pragma omp parallel reduction(||: orf)
+  for (int i=0; i < N; ++i)
+    orf = orf || rf[i];
+
+  #pragma omp parallel for reduction(||: ord)
+  for (int i=0; i < N; ++i)
+    ord = ord || rcd[i];
+
+  #pragma omp parallel for simd reduction(||: orfc)
+  for (int i=0; i < N; ++i)
+    orfc = orfc || rcf[i];
+
+  #pragma omp parallel loop reduction(||: ordc)
+  for (int i=0; i < N; ++i)
+    ordc = ordc || rcd[i];
+
+  return orf + ord + __real__ orfc + __real__ ordc;
+}
+
+int
+reduction_or_teams ()
+{
+  char orf = 0;
+  short ord = 0;
+  int orfc = 0;
+  long ordc = 0;
+
+  #pragma omp teams distribute parallel for reduction(||: orf)
+  for (int i=0; i < N; ++i)
+    orf = orf || rf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(||: ord)
+  for (int i=0; i < N; ++i)
+    ord = ord || rcd[i];
+
+  #pragma omp teams distribute parallel for reduction(||: orfc)
+  for (int i=0; i < N; ++i)
+    orfc = orfc || rcf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(||: ordc)
+  for (int i=0; i < N; ++i)
+    ordc = ordc || rcd[i];
+
+  return orf + ord + __real__ orfc + __real__ ordc;
+}
+
+int
+reduction_and ()
+{
+  unsigned char andf = 1;
+  unsigned short andd = 1;
+  unsigned int andfc = 1;
+  unsigned long anddc = 1;
+
+  #pragma omp parallel reduction(&&: andf)
+  for (int i=0; i < N; ++i)
+    andf = andf && rf[i];
+
+  #pragma omp parallel for reduction(&&: andd)
+  for (int i=0; i < N; ++i)
+    andd = andd && rcd[i];
+
+  #pragma omp parallel for simd reduction(&&: andfc)
+  for (int i=0; i < N; ++i)
+    andfc = andfc && rcf[i];
+
+  #pragma omp parallel loop reduction(&&: anddc)
+  for (int i=0; i < N; ++i)
+    anddc = anddc && rcd[i];
+
+  return andf + andd + __real__ andfc + __real__ anddc;
+}
+
+int
+reduction_and_teams ()
+{
+  unsigned char andf = 1;
+  unsigned short andd = 1;
+  unsigned int andfc = 1;
+  unsigned long anddc = 1;
+
+  #pragma omp teams distribute parallel for reduction(&&: andf)
+  for (int i=0; i < N; ++i)
+    andf = andf && rf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(&&: andd)
+  for (int i=0; i < N; ++i)
+    andd = andd && rcd[i];
+
+  #pragma omp teams distribute parallel for reduction(&&: andfc)
+  for (int i=0; i < N; ++i)
+    andfc = andfc && rcf[i];
+
+  #pragma omp teams distribute parallel for simd reduction(&&: anddc)
+  for (int i=0; i < N; ++i)
+    anddc = anddc && rcd[i];
+
+  return andf + andd + __real__ andfc + __real__ anddc;
+}
+
+int
+main ()
+{
+  for (int i = 0; i < N; ++i)
+    {
+      rf[i] = 0;
+      rd[i] = 0;
+      rcf[i] = 0;
+      rcd[i] = 0;
+    }
+
+  if (reduction_or () != 0)
+    __builtin_abort ();
+  if (reduction_or_teams () != 0)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  rf[10] = 1.0;
+  rd[15] = 1.0;
+  rcf[10] = 1.0;
+  rcd[15] = 1.0i;
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  for (int i = 0; i < N; ++i)
+    {
+      rf[i] = 1;
+      rd[i] = 1;
+      rcf[i] = 1;
+      rcd[i] = 1;
+    }
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 4)
+    __builtin_abort ();
+  if (reduction_and_teams () != 4)
+    __builtin_abort ();
+
+  rf[10] = 0.0;
+  rd[15] = 0.0;
+  rcf[10] = 0.0;
+  rcd[15] = 0.0;
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/reduction-4.c b/libgomp/testsuite/libgomp.c-c++-common/reduction-4.c
new file mode 100644 (file)
index 0000000..a465e10
--- /dev/null
@@ -0,0 +1,194 @@
+/* C / C++'s logical AND and OR operators take any scalar argument
+   which compares (un)equal to 0 - the result 1 or 0 and of type int.
+
+   In this testcase, the int result is again converted to an integer complex
+   type.
+
+   While having a floating-point/complex array element with || and && can make
+   sense, having a complex reduction variable is odd but valid.
+
+   Test: int complex reduction variable + int complex array.  */
+
+#define N 1024
+_Complex char rcc[N];
+_Complex short rcs[N];
+_Complex int rci[N];
+_Complex long long rcl[N];
+
+int
+reduction_or ()
+{
+  _Complex char orc = 0;
+  _Complex short ors = 0;
+  _Complex int ori = 0;
+  _Complex long orl = 0;
+
+  #pragma omp parallel reduction(||: orc)
+  for (int i=0; i < N; ++i)
+    orc = orc || rcl[i];
+
+  #pragma omp parallel for reduction(||: ors)
+  for (int i=0; i < N; ++i)
+    ors = ors || rci[i];
+
+  #pragma omp parallel for simd reduction(||: ori)
+  for (int i=0; i < N; ++i)
+    ori = ori || rcs[i];
+
+  #pragma omp parallel loop reduction(||: orl)
+  for (int i=0; i < N; ++i)
+    orl = orl || rcc[i];
+
+  return __real__ (orc + ors + ori + orl) + __imag__ (orc + ors + ori + orl);
+}
+
+int
+reduction_or_teams ()
+{
+  _Complex char orc = 0;
+  _Complex short ors = 0;
+  _Complex int ori = 0;
+  _Complex long orl = 0;
+
+  #pragma omp teams distribute parallel for reduction(||: orc)
+  for (int i=0; i < N; ++i)
+    orc = orc || rcc[i];
+
+  #pragma omp teams distribute parallel for simd reduction(||: ors)
+  for (int i=0; i < N; ++i)
+    ors = ors || rcs[i];
+
+  #pragma omp teams distribute parallel for reduction(||: ori)
+  for (int i=0; i < N; ++i)
+    ori = ori || rci[i];
+
+  #pragma omp teams distribute parallel for simd reduction(||: orl)
+  for (int i=0; i < N; ++i)
+    orl = orl || rcl[i];
+
+  return __real__ (orc + ors + ori + orl) + __imag__ (orc + ors + ori + orl);
+}
+
+int
+reduction_and ()
+{
+  _Complex char andc = 1;
+  _Complex short ands = 1;
+  _Complex int andi = 1;
+  _Complex long andl = 1;
+
+  #pragma omp parallel reduction(&&: andc)
+  for (int i=0; i < N; ++i)
+    andc = andc && rcc[i];
+
+  #pragma omp parallel for reduction(&&: ands)
+  for (int i=0; i < N; ++i)
+    ands = ands && rcs[i];
+
+  #pragma omp parallel for simd reduction(&&: andi)
+  for (int i=0; i < N; ++i)
+    andi = andi && rci[i];
+
+  #pragma omp parallel loop reduction(&&: andl)
+  for (int i=0; i < N; ++i)
+    andl = andl && rcl[i];
+
+  return __real__ (andc + ands + andi + andl)
+        + __imag__ (andc + ands + andi + andl);
+}
+
+int
+reduction_and_teams ()
+{
+  _Complex char andc = 1;
+  _Complex short ands = 1;
+  _Complex int andi = 1;
+  _Complex long andl = 1;
+
+  #pragma omp teams distribute parallel for reduction(&&: andc)
+  for (int i=0; i < N; ++i)
+    andc = andc && rcl[i];
+
+  #pragma omp teams distribute parallel for simd reduction(&&: ands)
+  for (int i=0; i < N; ++i)
+    ands = ands && rci[i];
+
+  #pragma omp teams distribute parallel for reduction(&&: andi)
+  for (int i=0; i < N; ++i)
+    andi = andi && rcs[i];
+
+  #pragma omp teams distribute parallel for simd reduction(&&: andl)
+  for (int i=0; i < N; ++i)
+    andl = andl && rcc[i];
+
+  return __real__ (andc + ands + andi + andl)
+        + __imag__ (andc + ands + andi + andl);
+}
+
+int
+main ()
+{
+  for (int i = 0; i < N; ++i)
+    {
+      rcc[i] = 0;
+      rcs[i] = 0;
+      rci[i] = 0;
+      rcl[i] = 0;
+    }
+
+  if (reduction_or () != 0)
+    __builtin_abort ();
+  if (reduction_or_teams () != 0)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  rcc[10] = 1.0;
+  rcs[15] = 1.0i;
+  rci[10] = 1.0;
+  rcl[15] = 1.0i;
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  for (int i = 0; i < N; ++i)
+    {
+      rcc[i] = 1;
+      rcs[i] = 1i;
+      rci[i] = 1;
+      rcl[i] = 1 + 1i;
+    }
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 4)
+    __builtin_abort ();
+  if (reduction_and_teams () != 4)
+    __builtin_abort ();
+
+  rcc[10] = 0.0;
+  rcs[15] = 0.0;
+  rci[10] = 0.0;
+  rcl[15] = 0.0;
+
+  if (reduction_or () != 4)
+    __builtin_abort ();
+  if (reduction_or_teams () != 4)
+    __builtin_abort ();
+  if (reduction_and () != 0)
+    __builtin_abort ();
+  if (reduction_and_teams () != 0)
+    __builtin_abort ();
+
+  return 0;
+}