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)
This commit is contained in:
Tobias Burnus 2021-05-04 13:38:03 +02:00 committed by Jakub Jelinek
parent 2f49122aec
commit d2904de2cf
8 changed files with 856 additions and 21 deletions

View File

@ -14119,6 +14119,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)
@ -14137,14 +14139,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 ();
}

View File

@ -6030,6 +6030,8 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
case PLUS_EXPR:
case MULT_EXPR:
case MINUS_EXPR:
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
predefined = true;
break;
case MIN_EXPR:
@ -6045,12 +6047,6 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
break;
predefined = true;
break;
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
if (FLOAT_TYPE_P (type))
break;
predefined = true;
break;
default:
break;
}

View File

@ -6376,6 +6376,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))
{
@ -6424,7 +6429,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]);
@ -6443,8 +6461,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);
}
@ -7384,13 +7416,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);
@ -7495,7 +7546,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);
}
@ -7529,7 +7592,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);
}

View 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'" } */
;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}