aboutsummaryrefslogtreecommitdiff
path: root/libgomp
diff options
context:
space:
mode:
authorTobias Burnus <tobias@codesourcery.com>2021-05-04 13:38:03 +0200
committerJakub Jelinek <jakub@redhat.com>2022-05-10 10:14:25 +0200
commit10a54fd7ad7197b508736b06fedb7ead4e1c3506 (patch)
tree126b4e4441d8705861d4ef6c533d119f4924022a /libgomp
parent2adeae7ab5f7bd274f3dda58baa04710699e59be (diff)
downloadgcc-10a54fd7ad7197b508736b06fedb7ead4e1c3506.zip
gcc-10a54fd7ad7197b508736b06fedb7ead4e1c3506.tar.gz
gcc-10a54fd7ad7197b508736b06fedb7ead4e1c3506.tar.bz2
OpenMP: Support complex/float in && and || reduction
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)
Diffstat (limited to 'libgomp')
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/reduction-1.c192
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/reduction-2.c192
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/reduction-3.c192
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/reduction-4.c194
4 files changed, 770 insertions, 0 deletions
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
index 0000000..89a4153
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/reduction-1.c
@@ -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
index 0000000..bdcba86
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/reduction-2.c
@@ -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
index 0000000..0f09aab
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/reduction-3.c
@@ -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
index 0000000..a465e10
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/reduction-4.c
@@ -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;
+}