OpenMP: C++ support for imperfectly-nested loops
OpenMP 5.0 removed the restriction that multiple collapsed loops must be perfectly nested, allowing "intervening code" (including nested BLOCKs) before or after each nested loop. In GCC this code is moved into the inner loop body by the respective front ends. This patch changes the C++ front end to use recursive descent parsing on nested loops within an "omp for" construct, rather than an iterative approach, in order to preserve proper nesting of compound statements. Preserving cleanups (destructors) for class objects declared in intervening code and loop initializers complicates moving the former into the body of the loop; this is handled by parsing the entire construct before reassembling any of it. gcc/cp/ChangeLog * cp-tree.h (cp_convert_omp_range_for): Adjust declaration. * parser.cc (struct omp_for_parse_data): New. (cp_parser_postfix_expression): Diagnose calls to OpenMP runtime in intervening code. (check_omp_intervening_code): New. (cp_parser_statement_seq_opt): Special-case nested loops, blocks, and other constructs for OpenMP loops. (cp_parser_iteration_statement): Reject loops in intervening code. (cp_parser_omp_for_loop_init): Expand comments and tweak the interface slightly to better distinguish input/output parameters. (cp_convert_omp_range_for): Likewise. (cp_parser_omp_loop_nest): New, split from cp_parser_omp_for_loop and largely rewritten. Add more comments. (insert_structured_blocks): New. (find_structured_blocks): New. (struct sit_data, substitute_in_tree_walker, substitute_in_tree): New. (fixup_blocks_walker): New. (cp_parser_omp_for_loop): Rewrite to use recursive descent instead of a loop. Add logic to reshuffle the bits of code collected during parsing so intervening code gets moved to the loop body. (cp_parser_omp_loop): Remove call to finish_omp_for_block, which is now redundant. (cp_parser_omp_simd): Likewise. (cp_parser_omp_for): Likewise. (cp_parser_omp_distribute): Likewise. (cp_parser_oacc_loop): Likewise. (cp_parser_omp_taskloop): Likewise. (cp_parser_pragma): Reject OpenMP pragmas in intervening code. * parser.h (struct cp_parser): Add omp_for_parse_state field. * pt.cc (tsubst_omp_for_iterator): Adjust call to cp_convert_omp_range_for. * semantics.cc (finish_omp_for): Try harder to preserve location of loop variable init expression for use in diagnostics. (struct fofb_data, finish_omp_for_block_walker): New. (finish_omp_for_block): Allow variables to be bound in a BIND_EXPR nested inside BIND instead of directly in BIND itself. gcc/testsuite/ChangeLog * c-c++-common/goacc/tile-2.c: Adjust expected error patterns. * g++.dg/gomp/attrs-imperfect1.C: New test. * g++.dg/gomp/attrs-imperfect2.C: New test. * g++.dg/gomp/attrs-imperfect3.C: New test. * g++.dg/gomp/attrs-imperfect4.C: New test. * g++.dg/gomp/attrs-imperfect5.C: New test. * g++.dg/gomp/pr41967.C: Adjust expected error patterns. * g++.dg/gomp/tpl-imperfect-gotos.C: New test. * g++.dg/gomp/tpl-imperfect-invalid-scope.C: New test. libgomp/ChangeLog * testsuite/libgomp.c++/attrs-imperfect1.C: New test. * testsuite/libgomp.c++/attrs-imperfect2.C: New test. * testsuite/libgomp.c++/attrs-imperfect3.C: New test. * testsuite/libgomp.c++/attrs-imperfect4.C: New test. * testsuite/libgomp.c++/attrs-imperfect5.C: New test. * testsuite/libgomp.c++/attrs-imperfect6.C: New test. * testsuite/libgomp.c++/imperfect-class-1.C: New test. * testsuite/libgomp.c++/imperfect-class-2.C: New test. * testsuite/libgomp.c++/imperfect-class-3.C: New test. * testsuite/libgomp.c++/imperfect-destructor.C: New test. * testsuite/libgomp.c++/imperfect-template-1.C: New test. * testsuite/libgomp.c++/imperfect-template-2.C: New test. * testsuite/libgomp.c++/imperfect-template-3.C: New test.
This commit is contained in:
parent
143151ac20
commit
53891f18f3
27 changed files with 3239 additions and 419 deletions
|
@ -7313,7 +7313,7 @@ extern bool maybe_clone_body (tree);
|
|||
/* In parser.cc */
|
||||
extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool,
|
||||
unsigned short, bool);
|
||||
extern void cp_convert_omp_range_for (tree &, vec<tree, va_gc> *, tree &,
|
||||
extern void cp_convert_omp_range_for (tree &, tree &, tree &,
|
||||
tree &, tree &, tree &, tree &, tree &);
|
||||
extern void cp_finish_omp_range_for (tree, tree);
|
||||
extern bool parsing_nsdmi (void);
|
||||
|
|
1337
gcc/cp/parser.cc
1337
gcc/cp/parser.cc
File diff suppressed because it is too large
Load diff
|
@ -435,6 +435,9 @@ struct GTY(()) cp_parser {
|
|||
specification, if any, or UNKNOWN_LOCATION otherwise. */
|
||||
location_t innermost_linkage_specification_location;
|
||||
|
||||
/* Pointer to state for parsing omp_loops. Managed by
|
||||
cp_parser_omp_for_loop in parser.cc and not used outside that file. */
|
||||
struct omp_for_parse_data * GTY((skip)) omp_for_parse_state;
|
||||
};
|
||||
|
||||
/* In parser.cc */
|
||||
|
|
|
@ -18485,7 +18485,8 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv,
|
|||
tree this_pre_body = NULL_TREE;
|
||||
tree orig_init = NULL_TREE;
|
||||
tree orig_decl = NULL_TREE;
|
||||
cp_convert_omp_range_for (this_pre_body, NULL, decl, orig_decl, init,
|
||||
tree init_sl = NULL_TREE;
|
||||
cp_convert_omp_range_for (this_pre_body, init_sl, decl, orig_decl, init,
|
||||
orig_init, cond, incr);
|
||||
if (orig_decl)
|
||||
{
|
||||
|
|
|
@ -10541,6 +10541,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
|
|||
int i;
|
||||
int collapse = 1;
|
||||
int ordered = 0;
|
||||
auto_vec<location_t> init_locv;
|
||||
|
||||
gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv));
|
||||
gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv));
|
||||
|
@ -10569,6 +10570,28 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
|
|||
incr = TREE_VEC_ELT (incrv, i);
|
||||
elocus = locus;
|
||||
|
||||
/* We are going to throw out the init's original MODIFY_EXPR or
|
||||
MODOP_EXPR below. Save its location so we can use it when
|
||||
reconstructing the expression farther down. Alternatively, if the
|
||||
initializer is a binding of the iteration variable, save
|
||||
that location. Any of these locations in the initialization clause
|
||||
for the current nested loop are better than using the argument locus,
|
||||
that points to the "for" of the the outermost loop in the nest. */
|
||||
if (init && EXPR_HAS_LOCATION (init))
|
||||
elocus = EXPR_LOCATION (init);
|
||||
else if (decl && INDIRECT_REF_P (decl) && EXPR_HAS_LOCATION (decl))
|
||||
/* This can happen for class iterators. */
|
||||
elocus = EXPR_LOCATION (decl);
|
||||
else if (decl && DECL_P (decl))
|
||||
{
|
||||
if (DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
|
||||
elocus = DECL_SOURCE_LOCATION (decl);
|
||||
else if (DECL_INITIAL (decl)
|
||||
&& EXPR_HAS_LOCATION (DECL_INITIAL (decl)))
|
||||
elocus = EXPR_LOCATION (DECL_INITIAL (decl));
|
||||
}
|
||||
init_locv.safe_push (elocus);
|
||||
|
||||
if (decl == NULL)
|
||||
{
|
||||
if (init != NULL)
|
||||
|
@ -10597,9 +10620,6 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
|
|||
}
|
||||
}
|
||||
|
||||
if (init && EXPR_HAS_LOCATION (init))
|
||||
elocus = EXPR_LOCATION (init);
|
||||
|
||||
if (cond == global_namespace)
|
||||
continue;
|
||||
|
||||
|
@ -10646,8 +10666,8 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
|
|||
again and going through the cp_build_modify_expr path below when
|
||||
we instantiate the thing. */
|
||||
TREE_VEC_ELT (initv, i)
|
||||
= build2 (MODIFY_EXPR, void_type_node, TREE_VEC_ELT (declv, i),
|
||||
TREE_VEC_ELT (initv, i));
|
||||
= build2_loc (init_locv[i], MODIFY_EXPR, void_type_node,
|
||||
TREE_VEC_ELT (declv, i), TREE_VEC_ELT (initv, i));
|
||||
}
|
||||
|
||||
TREE_TYPE (stmt) = void_type_node;
|
||||
|
@ -10676,10 +10696,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
|
|||
incr = TREE_VEC_ELT (incrv, i);
|
||||
if (orig_incr)
|
||||
TREE_VEC_ELT (orig_incr, i) = incr;
|
||||
elocus = locus;
|
||||
|
||||
if (init && EXPR_HAS_LOCATION (init))
|
||||
elocus = EXPR_LOCATION (init);
|
||||
elocus = init_locv[i];
|
||||
|
||||
if (!DECL_P (decl))
|
||||
{
|
||||
|
@ -10724,7 +10741,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
|
|||
init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init,
|
||||
tf_warning_or_error);
|
||||
else
|
||||
init = build2 (MODIFY_EXPR, void_type_node, decl, init);
|
||||
init = build2_loc (elocus, MODIFY_EXPR, void_type_node, decl, init);
|
||||
if (decl == error_mark_node || init == error_mark_node)
|
||||
return NULL;
|
||||
|
||||
|
@ -10896,47 +10913,71 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
|
|||
return omp_for;
|
||||
}
|
||||
|
||||
/* Fix up range for decls. Those decls were pushed into BIND's BIND_EXPR_VARS
|
||||
and need to be moved into the BIND_EXPR inside of the OMP_FOR's body. */
|
||||
/* Code walker for finish_omp_for_block: extract binding of DP->var
|
||||
from its current block and move it to a new BIND_EXPR DP->b
|
||||
surrounding the body of DP->omp_for. */
|
||||
|
||||
struct fofb_data {
|
||||
tree var;
|
||||
tree b;
|
||||
tree omp_for;
|
||||
};
|
||||
|
||||
static tree
|
||||
finish_omp_for_block_walker (tree *tp, int *walk_subtrees, void *dp)
|
||||
{
|
||||
struct fofb_data *fofb = (struct fofb_data *)dp;
|
||||
if (TREE_CODE (*tp) == BIND_EXPR)
|
||||
for (tree *p = &BIND_EXPR_VARS (*tp); *p; p = &DECL_CHAIN (*p))
|
||||
{
|
||||
if (*p == fofb->var)
|
||||
{
|
||||
*p = DECL_CHAIN (*p);
|
||||
if (fofb->b == NULL_TREE)
|
||||
{
|
||||
fofb->b = make_node (BLOCK);
|
||||
fofb->b = build3 (BIND_EXPR, void_type_node, NULL_TREE,
|
||||
OMP_FOR_BODY (fofb->omp_for), fofb->b);
|
||||
TREE_SIDE_EFFECTS (fofb->b) = 1;
|
||||
OMP_FOR_BODY (fofb->omp_for) = fofb->b;
|
||||
}
|
||||
DECL_CHAIN (fofb->var) = BIND_EXPR_VARS (fofb->b);
|
||||
BIND_EXPR_VARS (fofb->b) = fofb->var;
|
||||
BLOCK_VARS (BIND_EXPR_BLOCK (fofb->b)) = fofb->var;
|
||||
BLOCK_VARS (BIND_EXPR_BLOCK (*tp)) = BIND_EXPR_VARS (*tp);
|
||||
return *tp;
|
||||
}
|
||||
}
|
||||
if (TREE_CODE (*tp) != BIND_EXPR && TREE_CODE (*tp) != STATEMENT_LIST)
|
||||
*walk_subtrees = false;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Fix up range for decls. Those decls were pushed into BIND's
|
||||
BIND_EXPR_VARS, or that of a nested BIND_EXPR inside its body,
|
||||
and need to be moved into a new BIND_EXPR surrounding OMP_FOR's body
|
||||
so that processing of combined loop directives can find them. */
|
||||
tree
|
||||
finish_omp_for_block (tree bind, tree omp_for)
|
||||
{
|
||||
if (omp_for == NULL_TREE
|
||||
|| !OMP_FOR_ORIG_DECLS (omp_for)
|
||||
|| bind == NULL_TREE
|
||||
|| TREE_CODE (bind) != BIND_EXPR)
|
||||
|| bind == NULL_TREE)
|
||||
return bind;
|
||||
tree b = NULL_TREE;
|
||||
struct fofb_data fofb;
|
||||
fofb.b = NULL_TREE;
|
||||
fofb.omp_for = omp_for;
|
||||
for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (omp_for)); i++)
|
||||
if (TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (omp_for), i)) == TREE_LIST
|
||||
&& TREE_CHAIN (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (omp_for), i)))
|
||||
{
|
||||
tree v = TREE_CHAIN (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (omp_for), i));
|
||||
gcc_assert (BIND_EXPR_BLOCK (bind)
|
||||
&& (BIND_EXPR_VARS (bind)
|
||||
== BLOCK_VARS (BIND_EXPR_BLOCK (bind))));
|
||||
for (int j = 2; j < TREE_VEC_LENGTH (v); j++)
|
||||
for (tree *p = &BIND_EXPR_VARS (bind); *p; p = &DECL_CHAIN (*p))
|
||||
{
|
||||
if (*p == TREE_VEC_ELT (v, j))
|
||||
{
|
||||
tree var = *p;
|
||||
*p = DECL_CHAIN (*p);
|
||||
if (b == NULL_TREE)
|
||||
{
|
||||
b = make_node (BLOCK);
|
||||
b = build3 (BIND_EXPR, void_type_node, NULL_TREE,
|
||||
OMP_FOR_BODY (omp_for), b);
|
||||
TREE_SIDE_EFFECTS (b) = 1;
|
||||
OMP_FOR_BODY (omp_for) = b;
|
||||
}
|
||||
DECL_CHAIN (var) = BIND_EXPR_VARS (b);
|
||||
BIND_EXPR_VARS (b) = var;
|
||||
BLOCK_VARS (BIND_EXPR_BLOCK (b)) = var;
|
||||
}
|
||||
}
|
||||
BLOCK_VARS (BIND_EXPR_BLOCK (bind)) = BIND_EXPR_VARS (bind);
|
||||
{
|
||||
fofb.var = TREE_VEC_ELT (v, j);
|
||||
cp_walk_tree (&bind, finish_omp_for_block_walker,
|
||||
(void *)&fofb, NULL);
|
||||
}
|
||||
}
|
||||
return bind;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ int main ()
|
|||
#pragma acc parallel
|
||||
{
|
||||
#pragma acc loop tile (*,*)
|
||||
for (int ix = 0; ix < 30; ix++) /* { dg-error "not enough" "" { target c } } */
|
||||
; /* { dg-error "not enough" "" { target c++ } } */
|
||||
for (int ix = 0; ix < 30; ix++) /* { dg-error "not enough" } */
|
||||
;
|
||||
|
||||
#pragma acc loop tile (*,*)
|
||||
for (int ix = 0; ix < 30; ix++)
|
||||
|
|
38
gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C
Normal file
38
gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* { dg-do compile { target c++11 } } */
|
||||
|
||||
/* This test case is expected to fail due to errors. */
|
||||
|
||||
int f1 (int depth, int iter);
|
||||
int f2 (int depth, int iter);
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
[[ omp :: directive (for, collapse(3)) ]]
|
||||
for (i = 0; i < a1; i++)
|
||||
{
|
||||
f1 (0, i);
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
[[ omp :: directive (barrier) ]] ; /* { dg-error "intervening code must not contain OpenMP directives" } */
|
||||
f1 (1, j);
|
||||
if (i == 2)
|
||||
continue; /* { dg-error "invalid exit" } */
|
||||
else
|
||||
break; /* { dg-error "invalid exit" } */
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
f1 (2, k);
|
||||
f2 (2, k);
|
||||
}
|
||||
f2 (1, j);
|
||||
}
|
||||
for (k = 0; k < a3; k++) /* { dg-error "loop not permitted in intervening code " } */
|
||||
{
|
||||
f1 (2, k);
|
||||
f2 (2, k);
|
||||
}
|
||||
f2 (0, i);
|
||||
}
|
||||
}
|
34
gcc/testsuite/g++.dg/gomp/attrs-imperfect2.C
Normal file
34
gcc/testsuite/g++.dg/gomp/attrs-imperfect2.C
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* { dg-do compile { target c++11 } } */
|
||||
|
||||
/* This test case is expected to fail due to errors. */
|
||||
|
||||
/* These functions that are part of the OpenMP runtime API would ordinarily
|
||||
be declared in omp.h, but we don't have that here. */
|
||||
extern int omp_get_num_threads(void);
|
||||
extern int omp_get_max_threads(void);
|
||||
|
||||
int f1 (int depth, int iter);
|
||||
int f2 (int depth, int iter);
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
[[ omp :: directive (for, collapse(3)) ]]
|
||||
for (i = 0; i < a1; i++)
|
||||
{
|
||||
f1 (0, i);
|
||||
for (j = 0; j < omp_get_num_threads (); j++) /* This is OK */
|
||||
{
|
||||
f1 (1, omp_get_num_threads ()); /* { dg-error "not permitted in intervening code" } */
|
||||
for (k = omp_get_num_threads (); k < a3; k++) /* This is OK */
|
||||
{
|
||||
f1 (2, omp_get_num_threads ());
|
||||
f2 (2, omp_get_max_threads ());
|
||||
}
|
||||
f2 (1, omp_get_max_threads ()); /* { dg-error "not permitted in intervening code" } */
|
||||
}
|
||||
f2 (0, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
33
gcc/testsuite/g++.dg/gomp/attrs-imperfect3.C
Normal file
33
gcc/testsuite/g++.dg/gomp/attrs-imperfect3.C
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* { dg-do compile { target c++11 } } */
|
||||
|
||||
/* This test case is expected to fail due to errors. */
|
||||
|
||||
/* Test that the imperfectly-nested loops with the ordered clause gives
|
||||
an error, and that there is only one error (and not one on every
|
||||
intervening statement). */
|
||||
|
||||
int f1 (int depth, int iter);
|
||||
int f2 (int depth, int iter);
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
[[ omp :: directive (for, ordered(3)) ]]
|
||||
for (i = 0; i < a1; i++) /* { dg-error "inner loops must be perfectly nested" } */
|
||||
{
|
||||
f1 (0, i);
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
f1 (1, j);
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
f1 (2, k);
|
||||
f2 (2, k);
|
||||
}
|
||||
f2 (1, j);
|
||||
}
|
||||
f2 (0, i);
|
||||
}
|
||||
}
|
||||
|
33
gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C
Normal file
33
gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* { dg-do compile { target c++11 } } */
|
||||
|
||||
/* This test case is expected to fail due to errors. */
|
||||
|
||||
int f1 (int depth, int iter);
|
||||
int f2 (int depth, int iter);
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
[[ omp :: directive (for, collapse(4)) ]]
|
||||
for (i = 0; i < a1; i++) /* { dg-error "not enough nested loops" } */
|
||||
{
|
||||
f1 (0, i);
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
f1 (1, j);
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
/* According to the grammar, this is intervening code; we
|
||||
don't know that we are also missing a nested for loop
|
||||
until we have parsed this whole compound expression. */
|
||||
[[ omp :: directive (barrier) ]] ; /* { dg-error "intervening code must not contain OpenMP directives" } */
|
||||
f1 (2, k);
|
||||
f2 (2, k);
|
||||
}
|
||||
f2 (1, j);
|
||||
}
|
||||
f2 (0, i);
|
||||
}
|
||||
}
|
||||
|
57
gcc/testsuite/g++.dg/gomp/attrs-imperfect5.C
Normal file
57
gcc/testsuite/g++.dg/gomp/attrs-imperfect5.C
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* { dg-do compile { target c++11 } } */
|
||||
|
||||
/* This test case is expected to fail due to errors. */
|
||||
|
||||
int f1 (int depth, int iter);
|
||||
int f2 (int depth, int iter);
|
||||
int ijk (int x, int y, int z);
|
||||
void f3 (int sum);
|
||||
|
||||
/* This function isn't particularly meaningful, but it should compile without
|
||||
error. */
|
||||
int s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
int r = 0;
|
||||
|
||||
[[ omp :: directive (simd, collapse(3), reduction (inscan, +:r)) ]]
|
||||
for (i = 0; i < a1; i++)
|
||||
{
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
r = r + ijk (i, j, k);
|
||||
[[ omp :: directive (scan, exclusive (r)) ]] ;
|
||||
f3 (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Adding intervening code should trigger an error. */
|
||||
int s2 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
int r = 0;
|
||||
|
||||
[[ omp :: directive (simd, collapse(3), reduction (inscan, +:r)) ]]
|
||||
for (i = 0; i < a1; i++) /* { dg-error "inner loops must be perfectly nested" } */
|
||||
{
|
||||
f1 (0, i);
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
f1 (1, j);
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
r = r + ijk (i, j, k);
|
||||
[[ omp :: directive (scan, exclusive (r)) ]] ;
|
||||
f3 (r);
|
||||
}
|
||||
f2 (1, j);
|
||||
}
|
||||
f2 (0, i);
|
||||
}
|
||||
return r;
|
||||
}
|
|
@ -11,7 +11,7 @@ foo ()
|
|||
{
|
||||
for (int j = 0; j < 5; ++j)
|
||||
++sum;
|
||||
++sum; // { dg-error "collapsed loops not perfectly nested" }
|
||||
++sum;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
|
161
gcc/testsuite/g++.dg/gomp/tpl-imperfect-gotos.C
Normal file
161
gcc/testsuite/g++.dg/gomp/tpl-imperfect-gotos.C
Normal file
|
@ -0,0 +1,161 @@
|
|||
/* { dg-do compile } */
|
||||
|
||||
/* This file contains tests that are expected to fail. */
|
||||
|
||||
|
||||
/* These jumps are all OK since they are to/from the same structured block. */
|
||||
|
||||
template<typename T>
|
||||
void f1a (void)
|
||||
{
|
||||
#pragma omp for collapse(2)
|
||||
for (T i = 0; i < 64; ++i)
|
||||
{
|
||||
goto a; a:;
|
||||
for (T j = 0; j < 64; ++j)
|
||||
{
|
||||
goto c; c:;
|
||||
}
|
||||
goto b; b:;
|
||||
}
|
||||
}
|
||||
|
||||
/* Jump around loop body to/from different structured blocks of intervening
|
||||
code. */
|
||||
template<typename T>
|
||||
void f2a (void)
|
||||
{
|
||||
#pragma omp for collapse(2)
|
||||
for (T i = 0; i < 64; ++i)
|
||||
{
|
||||
goto a; a:;
|
||||
if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */
|
||||
for (T j = 0; j < 64; ++j)
|
||||
{
|
||||
goto c; c:;
|
||||
}
|
||||
goto b; b:;
|
||||
}
|
||||
}
|
||||
|
||||
/* Jump into loop body from intervening code. */
|
||||
template<typename T>
|
||||
void f3a (void)
|
||||
{
|
||||
#pragma omp for collapse(2)
|
||||
for (T i = 0; i < 64; ++i)
|
||||
{
|
||||
goto a; a:;
|
||||
if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */
|
||||
for (T j = 0; j < 64; ++j)
|
||||
{
|
||||
c: /* { dg-error "jump to label .c." } */
|
||||
;
|
||||
}
|
||||
goto b; b:;
|
||||
}
|
||||
}
|
||||
|
||||
/* Jump out of loop body to intervening code. */
|
||||
template<typename T>
|
||||
void f4a (void)
|
||||
{
|
||||
#pragma omp for collapse(2)
|
||||
for (T i = 0; i < 64; ++i)
|
||||
{
|
||||
goto a; a:;
|
||||
for (T j = 0; j < 64; ++j)
|
||||
if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */
|
||||
c:
|
||||
;
|
||||
goto b; b:;
|
||||
}
|
||||
}
|
||||
|
||||
/* The next group of tests use the GNU extension for local labels. Expected
|
||||
behavior is the same as the above group. */
|
||||
|
||||
/* These jumps are all OK since they are to/from the same structured block. */
|
||||
|
||||
template<typename T>
|
||||
void f1b (void)
|
||||
{
|
||||
#pragma omp for collapse(2)
|
||||
for (T i = 0; i < 64; ++i)
|
||||
{
|
||||
__label__ a, b, c;
|
||||
goto a; a:;
|
||||
for (T j = 0; j < 64; ++j)
|
||||
{
|
||||
goto c; c:;
|
||||
}
|
||||
goto b; b:;
|
||||
}
|
||||
}
|
||||
|
||||
/* Jump around loop body to/from different structured blocks of intervening
|
||||
code. */
|
||||
template<typename T>
|
||||
void f2b (void)
|
||||
{
|
||||
#pragma omp for collapse(2)
|
||||
for (T i = 0; i < 64; ++i)
|
||||
{
|
||||
__label__ a, b, c;
|
||||
goto a; a:;
|
||||
if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */
|
||||
for (T j = 0; j < 64; ++j)
|
||||
{
|
||||
goto c; c:;
|
||||
}
|
||||
goto b; b:;
|
||||
}
|
||||
}
|
||||
|
||||
/* Jump into loop body from intervening code. */
|
||||
template<typename T>
|
||||
void f3b (void)
|
||||
{
|
||||
#pragma omp for collapse(2)
|
||||
for (T i = 0; i < 64; ++i)
|
||||
{
|
||||
__label__ a, b, c;
|
||||
goto a; a:;
|
||||
if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */
|
||||
for (T j = 0; j < 64; ++j)
|
||||
{
|
||||
c: /* { dg-error "jump to label .c." } */
|
||||
;
|
||||
}
|
||||
goto b; b:;
|
||||
}
|
||||
}
|
||||
|
||||
/* Jump out of loop body to intervening code. */
|
||||
template<typename T>
|
||||
void f4b (void)
|
||||
{
|
||||
#pragma omp for collapse(2)
|
||||
for (T i = 0; i < 64; ++i)
|
||||
{
|
||||
__label__ a, b, c;
|
||||
goto a; a:;
|
||||
for (T j = 0; j < 64; ++j)
|
||||
if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */
|
||||
c:
|
||||
;
|
||||
goto b; b:;
|
||||
}
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
f1a<int> ();
|
||||
f2a<int> ();
|
||||
f3a<int> ();
|
||||
f4a<int> ();
|
||||
f1b<int> ();
|
||||
f2b<int> ();
|
||||
f3b<int> ();
|
||||
f4b<int> ();
|
||||
}
|
94
gcc/testsuite/g++.dg/gomp/tpl-imperfect-invalid-scope.C
Normal file
94
gcc/testsuite/g++.dg/gomp/tpl-imperfect-invalid-scope.C
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* { dg-do compile } */
|
||||
|
||||
/* Check that various cases of invalid references to variables bound
|
||||
in an intervening code scope are diagnosed and do not ICE. This test
|
||||
is expected to produce errors. */
|
||||
|
||||
template<typename T>
|
||||
extern void foo (T, T);
|
||||
|
||||
template<typename T>
|
||||
void f1 (void)
|
||||
{
|
||||
#pragma omp for collapse (2)
|
||||
for (T i = 0; i < 64; i++)
|
||||
{
|
||||
T v = (i + 4) * 2;
|
||||
for (T j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */
|
||||
foo (i, j);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void f2 (void)
|
||||
{
|
||||
#pragma omp for collapse (2)
|
||||
for (T i = 0; i < 64; i++)
|
||||
{
|
||||
T v = (i + 4) * 2;
|
||||
for (T j = 0; j < v; j++) /* { dg-error "end test is bound in intervening code" } */
|
||||
foo (i, j);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void f3 (void)
|
||||
{
|
||||
#pragma omp for collapse (2)
|
||||
for (T i = 0; i < 64; i++)
|
||||
{
|
||||
T v = (i + 4) * 2;
|
||||
for (T j = 0; j < 64; j = j + v) /* { dg-error "increment expression is bound in intervening code" } */
|
||||
foo (i, j);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void f4 (void)
|
||||
{
|
||||
#pragma omp for collapse (2)
|
||||
for (T i = 0; i < 64; i++)
|
||||
{
|
||||
T v = 8;
|
||||
for (T j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */
|
||||
foo (i, j);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void f5 (void)
|
||||
{
|
||||
#pragma omp for collapse (2)
|
||||
for (T i = 0; i < 64; i++)
|
||||
{
|
||||
T j;
|
||||
for (j = 0; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */
|
||||
foo (i, j);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void f6 (void)
|
||||
{
|
||||
#pragma omp for collapse (2)
|
||||
for (T i = 0; i < 64; i++)
|
||||
{
|
||||
T j;
|
||||
{
|
||||
T v = 8;
|
||||
for (j = v; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */
|
||||
/* { dg-error "initializer is bound in intervening code" "" { target *-*-* } .-1 } */
|
||||
foo (i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
f1<int> ();
|
||||
f2<int> ();
|
||||
f3<int> ();
|
||||
f4<int> ();
|
||||
f5<int> ();
|
||||
f6<int> ();
|
||||
}
|
76
libgomp/testsuite/libgomp.c++/attrs-imperfect1.C
Normal file
76
libgomp/testsuite/libgomp.c++/attrs-imperfect1.C
Normal file
|
@ -0,0 +1,76 @@
|
|||
/* { dg-do run } */
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
int f1 (int depth, int iter)
|
||||
{
|
||||
f1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int f2 (int depth, int iter)
|
||||
{
|
||||
f2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
[[ omp :: directive (for, collapse(3)) ]]
|
||||
for (i = 0; i < a1; i++)
|
||||
{
|
||||
f1 (0, i);
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
f1 (1, j);
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
f1 (2, k);
|
||||
f2 (2, k);
|
||||
}
|
||||
f2 (1, j);
|
||||
}
|
||||
f2 (0, i);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
s1 (3, 4, 5);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
114
libgomp/testsuite/libgomp.c++/attrs-imperfect2.C
Normal file
114
libgomp/testsuite/libgomp.c++/attrs-imperfect2.C
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* { dg-do run } */
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
static int g1count[3], g2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
int f1 (int depth, int iter)
|
||||
{
|
||||
f1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int f2 (int depth, int iter)
|
||||
{
|
||||
f2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g1 (int depth, int iter)
|
||||
{
|
||||
g1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g2 (int depth, int iter)
|
||||
{
|
||||
g2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
[[ omp :: directive (for, collapse(3)) ]]
|
||||
for (i = 0; i < a1; i++)
|
||||
{
|
||||
f1 (0, i);
|
||||
{
|
||||
g1 (0, i);
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
f1 (1, j);
|
||||
{
|
||||
g1 (1, j);
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
f1 (2, k);
|
||||
{
|
||||
g1 (2, k);
|
||||
g2 (2, k);
|
||||
}
|
||||
f2 (2, k);
|
||||
}
|
||||
g2 (1, j);
|
||||
}
|
||||
f2 (1, j);
|
||||
}
|
||||
g2 (0, i);
|
||||
}
|
||||
f2 (0, i);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
g1count[0] = 0;
|
||||
g1count[1] = 0;
|
||||
g1count[2] = 0;
|
||||
g2count[0] = 0;
|
||||
g2count[1] = 0;
|
||||
g2count[2] = 0;
|
||||
|
||||
s1 (3, 4, 5);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
if (g1count[0] != f1count[0]) abort ();
|
||||
if (g2count[0] != f1count[0]) abort ();
|
||||
if (g1count[1] != f1count[1]) abort ();
|
||||
if (g2count[1] != f1count[1]) abort ();
|
||||
if (g1count[2] != f1count[2]) abort ();
|
||||
if (g2count[2] != f1count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
119
libgomp/testsuite/libgomp.c++/attrs-imperfect3.C
Normal file
119
libgomp/testsuite/libgomp.c++/attrs-imperfect3.C
Normal file
|
@ -0,0 +1,119 @@
|
|||
/* { dg-do run } */
|
||||
|
||||
/* Like imperfect2.c, but includes bindings in the blocks. */
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
static int g1count[3], g2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
int f1 (int depth, int iter)
|
||||
{
|
||||
f1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int f2 (int depth, int iter)
|
||||
{
|
||||
f2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g1 (int depth, int iter)
|
||||
{
|
||||
g1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g2 (int depth, int iter)
|
||||
{
|
||||
g2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
[[ omp :: directive (for, collapse(3)) ]]
|
||||
for (i = 0; i < a1; i++)
|
||||
{
|
||||
int local0 = 0;
|
||||
f1 (local0, i);
|
||||
{
|
||||
g1 (local0, i);
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
int local1 = 1;
|
||||
f1 (local1, j);
|
||||
{
|
||||
g1 (local1, j);
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
int local2 = 2;
|
||||
f1 (local2, k);
|
||||
{
|
||||
g1 (local2, k);
|
||||
g2 (local2, k);
|
||||
}
|
||||
f2 (local2, k);
|
||||
}
|
||||
g2 (local1, j);
|
||||
}
|
||||
f2 (local1, j);
|
||||
}
|
||||
g2 (local0, i);
|
||||
}
|
||||
f2 (local0, i);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
g1count[0] = 0;
|
||||
g1count[1] = 0;
|
||||
g1count[2] = 0;
|
||||
g2count[0] = 0;
|
||||
g2count[1] = 0;
|
||||
g2count[2] = 0;
|
||||
|
||||
s1 (3, 4, 5);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
if (g1count[0] != f1count[0]) abort ();
|
||||
if (g2count[0] != f1count[0]) abort ();
|
||||
if (g1count[1] != f1count[1]) abort ();
|
||||
if (g2count[1] != f1count[1]) abort ();
|
||||
if (g1count[2] != f1count[2]) abort ();
|
||||
if (g2count[2] != f1count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
117
libgomp/testsuite/libgomp.c++/attrs-imperfect4.C
Normal file
117
libgomp/testsuite/libgomp.c++/attrs-imperfect4.C
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* { dg-do run } */
|
||||
|
||||
/* Like imperfect2.c, but includes blocks that are themselves intervening
|
||||
code. */
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
static int g1count[3], g2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
int f1 (int depth, int iter)
|
||||
{
|
||||
f1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int f2 (int depth, int iter)
|
||||
{
|
||||
f2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g1 (int depth, int iter)
|
||||
{
|
||||
g1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g2 (int depth, int iter)
|
||||
{
|
||||
g2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
[[ omp :: directive (for, collapse(3)) ]]
|
||||
for (i = 0; i < a1; i++)
|
||||
{
|
||||
{ f1 (0, i); }
|
||||
{
|
||||
g1 (0, i);
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
{ f1 (1, j); }
|
||||
{
|
||||
{ g1 (1, j); }
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
f1 (2, k);
|
||||
{
|
||||
g1 (2, k);
|
||||
g2 (2, k);
|
||||
}
|
||||
f2 (2, k);
|
||||
}
|
||||
{ g2 (1, j); }
|
||||
}
|
||||
{ f2 (1, j); }
|
||||
}
|
||||
{ g2 (0, i); }
|
||||
}
|
||||
{ f2 (0, i); }
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
g1count[0] = 0;
|
||||
g1count[1] = 0;
|
||||
g1count[2] = 0;
|
||||
g2count[0] = 0;
|
||||
g2count[1] = 0;
|
||||
g2count[2] = 0;
|
||||
|
||||
s1 (3, 4, 5);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
if (g1count[0] != f1count[0]) abort ();
|
||||
if (g2count[0] != f1count[0]) abort ();
|
||||
if (g1count[1] != f1count[1]) abort ();
|
||||
if (g2count[1] != f1count[1]) abort ();
|
||||
if (g1count[2] != f1count[2]) abort ();
|
||||
if (g2count[2] != f1count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
49
libgomp/testsuite/libgomp.c++/attrs-imperfect5.C
Normal file
49
libgomp/testsuite/libgomp.c++/attrs-imperfect5.C
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* { dg-do run } */
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
static int inner_loop_count = 0;
|
||||
static int intervening_code_count = 0;
|
||||
|
||||
void
|
||||
g (int x, int y)
|
||||
{
|
||||
inner_loop_count++;
|
||||
}
|
||||
|
||||
int
|
||||
foo (int imax, int jmax)
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
[[ omp :: directive (for, collapse(2)) ]]
|
||||
for (int i = 0; i < imax; ++i)
|
||||
{
|
||||
/* All the intervening code at the same level must be executed
|
||||
the same number of times. */
|
||||
++intervening_code_count;
|
||||
for (int j = 0; j < jmax; ++j)
|
||||
{
|
||||
g (i, j);
|
||||
}
|
||||
/* This is the outer j, not the one from the inner collapsed loop. */
|
||||
++j;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int j = foo (5, 3);
|
||||
if (j != intervening_code_count)
|
||||
abort ();
|
||||
if (inner_loop_count != 5 * 3)
|
||||
abort ();
|
||||
if (intervening_code_count < 5 || intervening_code_count > 5 * 3)
|
||||
abort ();
|
||||
}
|
115
libgomp/testsuite/libgomp.c++/attrs-imperfect6.C
Normal file
115
libgomp/testsuite/libgomp.c++/attrs-imperfect6.C
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* { dg-do run } */
|
||||
|
||||
/* Like imperfect4.c, but bind the iteration variables in the loops. */
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
static int g1count[3], g2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
int f1 (int depth, int iter)
|
||||
{
|
||||
f1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int f2 (int depth, int iter)
|
||||
{
|
||||
f2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g1 (int depth, int iter)
|
||||
{
|
||||
g1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g2 (int depth, int iter)
|
||||
{
|
||||
g2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
|
||||
[[ omp :: directive (for, collapse(3)) ]]
|
||||
for (int i = 0; i < a1; i++)
|
||||
{
|
||||
{ f1 (0, i); }
|
||||
{
|
||||
g1 (0, i);
|
||||
for (int j = 0; j < a2; j++)
|
||||
{
|
||||
{ f1 (1, j); }
|
||||
{
|
||||
{ g1 (1, j); }
|
||||
for (int k = 0; k < a3; k++)
|
||||
{
|
||||
f1 (2, k);
|
||||
{
|
||||
g1 (2, k);
|
||||
g2 (2, k);
|
||||
}
|
||||
f2 (2, k);
|
||||
}
|
||||
{ g2 (1, j); }
|
||||
}
|
||||
{ f2 (1, j); }
|
||||
}
|
||||
{ g2 (0, i); }
|
||||
}
|
||||
{ f2 (0, i); }
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
g1count[0] = 0;
|
||||
g1count[1] = 0;
|
||||
g1count[2] = 0;
|
||||
g2count[0] = 0;
|
||||
g2count[1] = 0;
|
||||
g2count[2] = 0;
|
||||
|
||||
s1 (3, 4, 5);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
if (g1count[0] != f1count[0]) abort ();
|
||||
if (g2count[0] != f1count[0]) abort ();
|
||||
if (g1count[1] != f1count[1]) abort ();
|
||||
if (g2count[1] != f1count[1]) abort ();
|
||||
if (g1count[2] != f1count[2]) abort ();
|
||||
if (g2count[2] != f1count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
169
libgomp/testsuite/libgomp.c++/imperfect-class-1.C
Normal file
169
libgomp/testsuite/libgomp.c++/imperfect-class-1.C
Normal file
|
@ -0,0 +1,169 @@
|
|||
// { dg-do run }
|
||||
// Test that class iterators and imperfectly-nested loops work together.
|
||||
// This variant tests initialization by assignment.
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
typedef int T;
|
||||
typedef int S;
|
||||
|
||||
class I
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
I ();
|
||||
~I ();
|
||||
I (T *);
|
||||
I (const I &);
|
||||
T &operator * ();
|
||||
T *operator -> ();
|
||||
T &operator [] (const difference_type &) const;
|
||||
I &operator = (const I &);
|
||||
I &operator ++ ();
|
||||
I operator ++ (int);
|
||||
I &operator -- ();
|
||||
I operator -- (int);
|
||||
I &operator += (const difference_type &);
|
||||
I &operator -= (const difference_type &);
|
||||
I operator + (const difference_type &) const;
|
||||
I operator - (const difference_type &) const;
|
||||
friend bool operator == (I &, I &);
|
||||
friend bool operator == (const I &, const I &);
|
||||
friend bool operator < (I &, I &);
|
||||
friend bool operator < (const I &, const I &);
|
||||
friend bool operator <= (I &, I &);
|
||||
friend bool operator <= (const I &, const I &);
|
||||
friend bool operator > (I &, I &);
|
||||
friend bool operator > (const I &, const I &);
|
||||
friend bool operator >= (I &, I &);
|
||||
friend bool operator >= (const I &, const I &);
|
||||
friend typename I::difference_type operator - (I &, I &);
|
||||
friend typename I::difference_type operator - (const I &, const I &);
|
||||
friend I operator + (typename I::difference_type , const I &);
|
||||
private:
|
||||
T *p;
|
||||
};
|
||||
I::I () : p (0) {}
|
||||
I::~I () { p = (T *) 0; }
|
||||
I::I (T *x) : p (x) {}
|
||||
I::I (const I &x) : p (x.p) {}
|
||||
T &I::operator * () { return *p; }
|
||||
T *I::operator -> () { return p; }
|
||||
T &I::operator [] (const difference_type &x) const { return p[x]; }
|
||||
I &I::operator = (const I &x) { p = x.p; return *this; }
|
||||
I &I::operator ++ () { ++p; return *this; }
|
||||
I I::operator ++ (int) { return I (p++); }
|
||||
I &I::operator -- () { --p; return *this; }
|
||||
I I::operator -- (int) { return I (p--); }
|
||||
I &I::operator += (const difference_type &x) { p += x; return *this; }
|
||||
I &I::operator -= (const difference_type &x) { p -= x; return *this; }
|
||||
I I::operator + (const difference_type &x) const { return I (p + x); }
|
||||
I I::operator - (const difference_type &x) const { return I (p - x); }
|
||||
bool operator == (I &x, I &y) { return x.p == y.p; }
|
||||
bool operator == (const I &x, const I &y) { return x.p == y.p; }
|
||||
bool operator != (I &x, I &y) { return !(x == y); }
|
||||
bool operator != (const I &x, const I &y) { return !(x == y); }
|
||||
bool operator < (I &x, I &y) { return x.p < y.p; }
|
||||
bool operator < (const I &x, const I &y) { return x.p < y.p; }
|
||||
bool operator <= (I &x, I &y) { return x.p <= y.p; }
|
||||
bool operator <= (const I &x, const I &y) { return x.p <= y.p; }
|
||||
bool operator > (I &x, I &y) { return x.p > y.p; }
|
||||
bool operator > (const I &x, const I &y) { return x.p > y.p; }
|
||||
bool operator >= (I &x, I &y) { return x.p >= y.p; }
|
||||
bool operator >= (const I &x, const I &y) { return x.p >= y.p; }
|
||||
typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; }
|
||||
typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; }
|
||||
I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); }
|
||||
|
||||
class J
|
||||
{
|
||||
public:
|
||||
J(const I &x, const I &y) : b (x), e (y) {}
|
||||
const I &begin ();
|
||||
const I &end ();
|
||||
private:
|
||||
I b, e;
|
||||
};
|
||||
|
||||
const I &J::begin () { return b; }
|
||||
const I &J::end () { return e; }
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
void f1 (int depth)
|
||||
{
|
||||
f1count[depth]++;
|
||||
}
|
||||
|
||||
void f2 (int depth)
|
||||
{
|
||||
f2count[depth]++;
|
||||
}
|
||||
|
||||
void s1 (J a1, J a2, J a3)
|
||||
{
|
||||
I i, j, k;
|
||||
|
||||
#pragma omp for collapse(3)
|
||||
for (i = a1.begin (); i < a1.end (); i++)
|
||||
{
|
||||
f1 (0);
|
||||
for (j = a2.begin (); j < a2.end (); j++)
|
||||
{
|
||||
f1 (1);
|
||||
for (k = a3.begin (); k < a3.end (); k++)
|
||||
{
|
||||
f1 (2);
|
||||
f2 (2);
|
||||
}
|
||||
f2 (1);
|
||||
}
|
||||
f2 (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
int index[] = {0, 1, 2, 3, 4, 5};
|
||||
|
||||
J x (&index[0], &index[3]);
|
||||
J y (&index[0], &index[4]);
|
||||
J z (&index[0], &index[5]);
|
||||
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
s1 (x, y, z);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
167
libgomp/testsuite/libgomp.c++/imperfect-class-2.C
Normal file
167
libgomp/testsuite/libgomp.c++/imperfect-class-2.C
Normal file
|
@ -0,0 +1,167 @@
|
|||
// { dg-do run }
|
||||
// Test that class iterators and imperfectly-nested loops work together.
|
||||
// This variant tests loop initialization by declaration.
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
typedef int T;
|
||||
typedef int S;
|
||||
|
||||
class I
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
I ();
|
||||
~I ();
|
||||
I (T *);
|
||||
I (const I &);
|
||||
T &operator * ();
|
||||
T *operator -> ();
|
||||
T &operator [] (const difference_type &) const;
|
||||
I &operator = (const I &);
|
||||
I &operator ++ ();
|
||||
I operator ++ (int);
|
||||
I &operator -- ();
|
||||
I operator -- (int);
|
||||
I &operator += (const difference_type &);
|
||||
I &operator -= (const difference_type &);
|
||||
I operator + (const difference_type &) const;
|
||||
I operator - (const difference_type &) const;
|
||||
friend bool operator == (I &, I &);
|
||||
friend bool operator == (const I &, const I &);
|
||||
friend bool operator < (I &, I &);
|
||||
friend bool operator < (const I &, const I &);
|
||||
friend bool operator <= (I &, I &);
|
||||
friend bool operator <= (const I &, const I &);
|
||||
friend bool operator > (I &, I &);
|
||||
friend bool operator > (const I &, const I &);
|
||||
friend bool operator >= (I &, I &);
|
||||
friend bool operator >= (const I &, const I &);
|
||||
friend typename I::difference_type operator - (I &, I &);
|
||||
friend typename I::difference_type operator - (const I &, const I &);
|
||||
friend I operator + (typename I::difference_type , const I &);
|
||||
private:
|
||||
T *p;
|
||||
};
|
||||
I::I () : p (0) {}
|
||||
I::~I () { p = (T *) 0; }
|
||||
I::I (T *x) : p (x) {}
|
||||
I::I (const I &x) : p (x.p) {}
|
||||
T &I::operator * () { return *p; }
|
||||
T *I::operator -> () { return p; }
|
||||
T &I::operator [] (const difference_type &x) const { return p[x]; }
|
||||
I &I::operator = (const I &x) { p = x.p; return *this; }
|
||||
I &I::operator ++ () { ++p; return *this; }
|
||||
I I::operator ++ (int) { return I (p++); }
|
||||
I &I::operator -- () { --p; return *this; }
|
||||
I I::operator -- (int) { return I (p--); }
|
||||
I &I::operator += (const difference_type &x) { p += x; return *this; }
|
||||
I &I::operator -= (const difference_type &x) { p -= x; return *this; }
|
||||
I I::operator + (const difference_type &x) const { return I (p + x); }
|
||||
I I::operator - (const difference_type &x) const { return I (p - x); }
|
||||
bool operator == (I &x, I &y) { return x.p == y.p; }
|
||||
bool operator == (const I &x, const I &y) { return x.p == y.p; }
|
||||
bool operator != (I &x, I &y) { return !(x == y); }
|
||||
bool operator != (const I &x, const I &y) { return !(x == y); }
|
||||
bool operator < (I &x, I &y) { return x.p < y.p; }
|
||||
bool operator < (const I &x, const I &y) { return x.p < y.p; }
|
||||
bool operator <= (I &x, I &y) { return x.p <= y.p; }
|
||||
bool operator <= (const I &x, const I &y) { return x.p <= y.p; }
|
||||
bool operator > (I &x, I &y) { return x.p > y.p; }
|
||||
bool operator > (const I &x, const I &y) { return x.p > y.p; }
|
||||
bool operator >= (I &x, I &y) { return x.p >= y.p; }
|
||||
bool operator >= (const I &x, const I &y) { return x.p >= y.p; }
|
||||
typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; }
|
||||
typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; }
|
||||
I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); }
|
||||
|
||||
class J
|
||||
{
|
||||
public:
|
||||
J(const I &x, const I &y) : b (x), e (y) {}
|
||||
const I &begin ();
|
||||
const I &end ();
|
||||
private:
|
||||
I b, e;
|
||||
};
|
||||
|
||||
const I &J::begin () { return b; }
|
||||
const I &J::end () { return e; }
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
void f1 (int depth)
|
||||
{
|
||||
f1count[depth]++;
|
||||
}
|
||||
|
||||
void f2 (int depth)
|
||||
{
|
||||
f2count[depth]++;
|
||||
}
|
||||
|
||||
void s1 (J a1, J a2, J a3)
|
||||
{
|
||||
#pragma omp for collapse(3)
|
||||
for (I i = a1.begin (); i < a1.end (); i++)
|
||||
{
|
||||
f1 (0);
|
||||
for (I j = a2.begin (); j < a2.end (); j++)
|
||||
{
|
||||
f1 (1);
|
||||
for (I k = a3.begin (); k < a3.end (); k++)
|
||||
{
|
||||
f1 (2);
|
||||
f2 (2);
|
||||
}
|
||||
f2 (1);
|
||||
}
|
||||
f2 (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
int index[] = {0, 1, 2, 3, 4, 5};
|
||||
|
||||
J x (&index[0], &index[3]);
|
||||
J y (&index[0], &index[4]);
|
||||
J z (&index[0], &index[5]);
|
||||
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
s1 (x, y, z);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
167
libgomp/testsuite/libgomp.c++/imperfect-class-3.C
Normal file
167
libgomp/testsuite/libgomp.c++/imperfect-class-3.C
Normal file
|
@ -0,0 +1,167 @@
|
|||
// { dg-do run }
|
||||
// Test that class iterators and imperfectly-nested loops work together.
|
||||
// This variant tests range for.
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
typedef int T;
|
||||
typedef int S;
|
||||
|
||||
class I
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
I ();
|
||||
~I ();
|
||||
I (T *);
|
||||
I (const I &);
|
||||
T &operator * ();
|
||||
T *operator -> ();
|
||||
T &operator [] (const difference_type &) const;
|
||||
I &operator = (const I &);
|
||||
I &operator ++ ();
|
||||
I operator ++ (int);
|
||||
I &operator -- ();
|
||||
I operator -- (int);
|
||||
I &operator += (const difference_type &);
|
||||
I &operator -= (const difference_type &);
|
||||
I operator + (const difference_type &) const;
|
||||
I operator - (const difference_type &) const;
|
||||
friend bool operator == (I &, I &);
|
||||
friend bool operator == (const I &, const I &);
|
||||
friend bool operator < (I &, I &);
|
||||
friend bool operator < (const I &, const I &);
|
||||
friend bool operator <= (I &, I &);
|
||||
friend bool operator <= (const I &, const I &);
|
||||
friend bool operator > (I &, I &);
|
||||
friend bool operator > (const I &, const I &);
|
||||
friend bool operator >= (I &, I &);
|
||||
friend bool operator >= (const I &, const I &);
|
||||
friend typename I::difference_type operator - (I &, I &);
|
||||
friend typename I::difference_type operator - (const I &, const I &);
|
||||
friend I operator + (typename I::difference_type , const I &);
|
||||
private:
|
||||
T *p;
|
||||
};
|
||||
I::I () : p (0) {}
|
||||
I::~I () { p = (T *) 0; }
|
||||
I::I (T *x) : p (x) {}
|
||||
I::I (const I &x) : p (x.p) {}
|
||||
T &I::operator * () { return *p; }
|
||||
T *I::operator -> () { return p; }
|
||||
T &I::operator [] (const difference_type &x) const { return p[x]; }
|
||||
I &I::operator = (const I &x) { p = x.p; return *this; }
|
||||
I &I::operator ++ () { ++p; return *this; }
|
||||
I I::operator ++ (int) { return I (p++); }
|
||||
I &I::operator -- () { --p; return *this; }
|
||||
I I::operator -- (int) { return I (p--); }
|
||||
I &I::operator += (const difference_type &x) { p += x; return *this; }
|
||||
I &I::operator -= (const difference_type &x) { p -= x; return *this; }
|
||||
I I::operator + (const difference_type &x) const { return I (p + x); }
|
||||
I I::operator - (const difference_type &x) const { return I (p - x); }
|
||||
bool operator == (I &x, I &y) { return x.p == y.p; }
|
||||
bool operator == (const I &x, const I &y) { return x.p == y.p; }
|
||||
bool operator != (I &x, I &y) { return !(x == y); }
|
||||
bool operator != (const I &x, const I &y) { return !(x == y); }
|
||||
bool operator < (I &x, I &y) { return x.p < y.p; }
|
||||
bool operator < (const I &x, const I &y) { return x.p < y.p; }
|
||||
bool operator <= (I &x, I &y) { return x.p <= y.p; }
|
||||
bool operator <= (const I &x, const I &y) { return x.p <= y.p; }
|
||||
bool operator > (I &x, I &y) { return x.p > y.p; }
|
||||
bool operator > (const I &x, const I &y) { return x.p > y.p; }
|
||||
bool operator >= (I &x, I &y) { return x.p >= y.p; }
|
||||
bool operator >= (const I &x, const I &y) { return x.p >= y.p; }
|
||||
typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; }
|
||||
typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; }
|
||||
I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); }
|
||||
|
||||
class J
|
||||
{
|
||||
public:
|
||||
J(const I &x, const I &y) : b (x), e (y) {}
|
||||
const I &begin ();
|
||||
const I &end ();
|
||||
private:
|
||||
I b, e;
|
||||
};
|
||||
|
||||
const I &J::begin () { return b; }
|
||||
const I &J::end () { return e; }
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
void f1 (int depth)
|
||||
{
|
||||
f1count[depth]++;
|
||||
}
|
||||
|
||||
void f2 (int depth)
|
||||
{
|
||||
f2count[depth]++;
|
||||
}
|
||||
|
||||
void s1 (J a1, J a2, J a3)
|
||||
{
|
||||
#pragma omp for collapse(3)
|
||||
for (auto i : a1)
|
||||
{
|
||||
f1 (0);
|
||||
for (auto j : a2)
|
||||
{
|
||||
f1 (1);
|
||||
for (auto k : a3)
|
||||
{
|
||||
f1 (2);
|
||||
f2 (2);
|
||||
}
|
||||
f2 (1);
|
||||
}
|
||||
f2 (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
int index[] = {0, 1, 2, 3, 4, 5};
|
||||
|
||||
J x (&index[0], &index[3]);
|
||||
J y (&index[0], &index[4]);
|
||||
J z (&index[0], &index[5]);
|
||||
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
s1 (x, y, z);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
135
libgomp/testsuite/libgomp.c++/imperfect-destructor.C
Normal file
135
libgomp/testsuite/libgomp.c++/imperfect-destructor.C
Normal file
|
@ -0,0 +1,135 @@
|
|||
/* { dg-do run } */
|
||||
|
||||
/* Make sure destructors are called for class variables bound
|
||||
in intervening code. */
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
static int g1count[3], g2count[3];
|
||||
|
||||
static int ccount[3], dcount[3];
|
||||
|
||||
class C {
|
||||
public:
|
||||
int n;
|
||||
C (int nn) { n = nn; ccount[n]++; }
|
||||
~C () { dcount[n]++; n = 0; }
|
||||
};
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
int f1 (int depth, int iter)
|
||||
{
|
||||
f1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int f2 (int depth, int iter)
|
||||
{
|
||||
f2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g1 (int depth, int iter)
|
||||
{
|
||||
g1count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int g2 (int depth, int iter)
|
||||
{
|
||||
g2count[depth]++;
|
||||
return iter;
|
||||
}
|
||||
|
||||
void s1 (int a1, int a2, int a3)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
#pragma omp for collapse(3)
|
||||
for (i = 0; i < a1; i++)
|
||||
{
|
||||
C local0(0);
|
||||
f1 (local0.n, i);
|
||||
{
|
||||
g1 (local0.n, i);
|
||||
for (j = 0; j < a2; j++)
|
||||
{
|
||||
C local1(1);
|
||||
f1 (local1.n, j);
|
||||
{
|
||||
g1 (local1.n, j);
|
||||
for (k = 0; k < a3; k++)
|
||||
{
|
||||
C local2(2);
|
||||
f1 (local2.n, k);
|
||||
{
|
||||
g1 (local2.n, k);
|
||||
g2 (local2.n, k);
|
||||
}
|
||||
f2 (local2.n, k);
|
||||
}
|
||||
g2 (local1.n, j);
|
||||
}
|
||||
f2 (local1.n, j);
|
||||
}
|
||||
g2 (local0.n, i);
|
||||
}
|
||||
f2 (local0.n, i);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
g1count[0] = 0;
|
||||
g1count[1] = 0;
|
||||
g1count[2] = 0;
|
||||
g2count[0] = 0;
|
||||
g2count[1] = 0;
|
||||
g2count[2] = 0;
|
||||
|
||||
s1 (3, 4, 5);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
if (g1count[0] != f1count[0]) abort ();
|
||||
if (g2count[0] != f1count[0]) abort ();
|
||||
if (g1count[1] != f1count[1]) abort ();
|
||||
if (g2count[1] != f1count[1]) abort ();
|
||||
if (g1count[2] != f1count[2]) abort ();
|
||||
if (g2count[2] != f1count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that each class object declared in intervening code was
|
||||
constructed and destructed an equal number of times. */
|
||||
if (ccount[0] != dcount[0]) abort ();
|
||||
if (ccount[1] != dcount[1]) abort ();
|
||||
if (ccount[2] != dcount[2]) abort ();
|
||||
}
|
172
libgomp/testsuite/libgomp.c++/imperfect-template-1.C
Normal file
172
libgomp/testsuite/libgomp.c++/imperfect-template-1.C
Normal file
|
@ -0,0 +1,172 @@
|
|||
// { dg-do run }
|
||||
// Test that template class iterators and imperfectly-nested loops
|
||||
// work together.
|
||||
// This variant tests initialization by assignment.
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
extern "C" void abort ();
|
||||
|
||||
template <typename T>
|
||||
class I
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
I ();
|
||||
~I ();
|
||||
I (T *);
|
||||
I (const I &);
|
||||
T &operator * ();
|
||||
T *operator -> ();
|
||||
T &operator [] (const difference_type &) const;
|
||||
I &operator = (const I &);
|
||||
I &operator ++ ();
|
||||
I operator ++ (int);
|
||||
I &operator -- ();
|
||||
I operator -- (int);
|
||||
I &operator += (const difference_type &);
|
||||
I &operator -= (const difference_type &);
|
||||
I operator + (const difference_type &) const;
|
||||
I operator - (const difference_type &) const;
|
||||
template <typename S> friend bool operator == (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator == (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator < (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator < (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator <= (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator > (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator > (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator >= (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
|
||||
template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
|
||||
template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
|
||||
template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
|
||||
private:
|
||||
T *p;
|
||||
};
|
||||
template <typename T> I<T>::I () : p (0) {}
|
||||
template <typename T> I<T>::~I () { p = (T *) 0; }
|
||||
template <typename T> I<T>::I (T *x) : p (x) {}
|
||||
template <typename T> I<T>::I (const I &x) : p (x.p) {}
|
||||
template <typename T> T &I<T>::operator * () { return *p; }
|
||||
template <typename T> T *I<T>::operator -> () { return p; }
|
||||
template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
|
||||
template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
|
||||
template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
|
||||
template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
|
||||
template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
|
||||
template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
|
||||
template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
|
||||
template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
|
||||
template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
|
||||
template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
|
||||
template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
|
||||
template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
|
||||
template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
|
||||
template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
|
||||
template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
|
||||
template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
|
||||
template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
|
||||
template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
|
||||
template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
|
||||
template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
|
||||
template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
|
||||
template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
|
||||
template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
|
||||
template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
|
||||
template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
|
||||
|
||||
template <typename T>
|
||||
class J
|
||||
{
|
||||
public:
|
||||
J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
|
||||
const I<T> &begin ();
|
||||
const I<T> &end ();
|
||||
private:
|
||||
I<T> b, e;
|
||||
};
|
||||
|
||||
template <typename T> const I<T> &J<T>::begin () { return b; }
|
||||
template <typename T> const I<T> &J<T>::end () { return e; }
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
void f1 (int depth)
|
||||
{
|
||||
f1count[depth]++;
|
||||
}
|
||||
|
||||
void f2 (int depth)
|
||||
{
|
||||
f2count[depth]++;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void s1 (J<T> a1, J<T> a2, J<T> a3)
|
||||
{
|
||||
I<T> i, j, k;
|
||||
|
||||
#pragma omp for collapse(3)
|
||||
for (i = a1.begin (); i < a1.end (); i++)
|
||||
{
|
||||
f1 (0);
|
||||
for (j = a2.begin (); j < a2.end (); j++)
|
||||
{
|
||||
f1 (1);
|
||||
for (k = a3.begin (); k < a3.end (); k++)
|
||||
{
|
||||
f1 (2);
|
||||
f2 (2);
|
||||
}
|
||||
f2 (1);
|
||||
}
|
||||
f2 (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
int index[] = {0, 1, 2, 3, 4, 5};
|
||||
|
||||
J<int> x (&index[0], &index[3]);
|
||||
J<int> y (&index[0], &index[4]);
|
||||
J<int> z (&index[0], &index[5]);
|
||||
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
s1<int> (x, y, z);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
170
libgomp/testsuite/libgomp.c++/imperfect-template-2.C
Normal file
170
libgomp/testsuite/libgomp.c++/imperfect-template-2.C
Normal file
|
@ -0,0 +1,170 @@
|
|||
// { dg-do run }
|
||||
// Test that template class iterators and imperfectly-nested loops
|
||||
// work together.
|
||||
// This variant tests initialization by declaration.
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
extern "C" void abort ();
|
||||
|
||||
template <typename T>
|
||||
class I
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
I ();
|
||||
~I ();
|
||||
I (T *);
|
||||
I (const I &);
|
||||
T &operator * ();
|
||||
T *operator -> ();
|
||||
T &operator [] (const difference_type &) const;
|
||||
I &operator = (const I &);
|
||||
I &operator ++ ();
|
||||
I operator ++ (int);
|
||||
I &operator -- ();
|
||||
I operator -- (int);
|
||||
I &operator += (const difference_type &);
|
||||
I &operator -= (const difference_type &);
|
||||
I operator + (const difference_type &) const;
|
||||
I operator - (const difference_type &) const;
|
||||
template <typename S> friend bool operator == (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator == (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator < (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator < (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator <= (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator > (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator > (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator >= (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
|
||||
template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
|
||||
template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
|
||||
template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
|
||||
private:
|
||||
T *p;
|
||||
};
|
||||
template <typename T> I<T>::I () : p (0) {}
|
||||
template <typename T> I<T>::~I () { p = (T *) 0; }
|
||||
template <typename T> I<T>::I (T *x) : p (x) {}
|
||||
template <typename T> I<T>::I (const I &x) : p (x.p) {}
|
||||
template <typename T> T &I<T>::operator * () { return *p; }
|
||||
template <typename T> T *I<T>::operator -> () { return p; }
|
||||
template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
|
||||
template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
|
||||
template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
|
||||
template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
|
||||
template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
|
||||
template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
|
||||
template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
|
||||
template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
|
||||
template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
|
||||
template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
|
||||
template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
|
||||
template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
|
||||
template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
|
||||
template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
|
||||
template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
|
||||
template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
|
||||
template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
|
||||
template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
|
||||
template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
|
||||
template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
|
||||
template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
|
||||
template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
|
||||
template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
|
||||
template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
|
||||
template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
|
||||
|
||||
template <typename T>
|
||||
class J
|
||||
{
|
||||
public:
|
||||
J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
|
||||
const I<T> &begin ();
|
||||
const I<T> &end ();
|
||||
private:
|
||||
I<T> b, e;
|
||||
};
|
||||
|
||||
template <typename T> const I<T> &J<T>::begin () { return b; }
|
||||
template <typename T> const I<T> &J<T>::end () { return e; }
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
void f1 (int depth)
|
||||
{
|
||||
f1count[depth]++;
|
||||
}
|
||||
|
||||
void f2 (int depth)
|
||||
{
|
||||
f2count[depth]++;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void s1 (J<T> a1, J<T> a2, J<T> a3)
|
||||
{
|
||||
#pragma omp for collapse(3)
|
||||
for (I<T> i = a1.begin (); i < a1.end (); i++)
|
||||
{
|
||||
f1 (0);
|
||||
for (I<T> j = a2.begin (); j < a2.end (); j++)
|
||||
{
|
||||
f1 (1);
|
||||
for (I<T> k = a3.begin (); k < a3.end (); k++)
|
||||
{
|
||||
f1 (2);
|
||||
f2 (2);
|
||||
}
|
||||
f2 (1);
|
||||
}
|
||||
f2 (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
int index[] = {0, 1, 2, 3, 4, 5};
|
||||
|
||||
J<int> x (&index[0], &index[3]);
|
||||
J<int> y (&index[0], &index[4]);
|
||||
J<int> z (&index[0], &index[5]);
|
||||
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
s1<int> (x, y, z);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
170
libgomp/testsuite/libgomp.c++/imperfect-template-3.C
Normal file
170
libgomp/testsuite/libgomp.c++/imperfect-template-3.C
Normal file
|
@ -0,0 +1,170 @@
|
|||
// { dg-do run }
|
||||
// Test that template class iterators and imperfectly-nested loops
|
||||
// work together.
|
||||
// This variant tests range for syntax.
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
extern "C" void abort ();
|
||||
|
||||
template <typename T>
|
||||
class I
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
I ();
|
||||
~I ();
|
||||
I (T *);
|
||||
I (const I &);
|
||||
T &operator * ();
|
||||
T *operator -> ();
|
||||
T &operator [] (const difference_type &) const;
|
||||
I &operator = (const I &);
|
||||
I &operator ++ ();
|
||||
I operator ++ (int);
|
||||
I &operator -- ();
|
||||
I operator -- (int);
|
||||
I &operator += (const difference_type &);
|
||||
I &operator -= (const difference_type &);
|
||||
I operator + (const difference_type &) const;
|
||||
I operator - (const difference_type &) const;
|
||||
template <typename S> friend bool operator == (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator == (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator < (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator < (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator <= (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator > (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator > (const I<S> &, const I<S> &);
|
||||
template <typename S> friend bool operator >= (I<S> &, I<S> &);
|
||||
template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
|
||||
template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
|
||||
template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
|
||||
template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
|
||||
private:
|
||||
T *p;
|
||||
};
|
||||
template <typename T> I<T>::I () : p (0) {}
|
||||
template <typename T> I<T>::~I () { p = (T *) 0; }
|
||||
template <typename T> I<T>::I (T *x) : p (x) {}
|
||||
template <typename T> I<T>::I (const I &x) : p (x.p) {}
|
||||
template <typename T> T &I<T>::operator * () { return *p; }
|
||||
template <typename T> T *I<T>::operator -> () { return p; }
|
||||
template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
|
||||
template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
|
||||
template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
|
||||
template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
|
||||
template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
|
||||
template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
|
||||
template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
|
||||
template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
|
||||
template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
|
||||
template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
|
||||
template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
|
||||
template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
|
||||
template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
|
||||
template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
|
||||
template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
|
||||
template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
|
||||
template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
|
||||
template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
|
||||
template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
|
||||
template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
|
||||
template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
|
||||
template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
|
||||
template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
|
||||
template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
|
||||
template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
|
||||
|
||||
template <typename T>
|
||||
class J
|
||||
{
|
||||
public:
|
||||
J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
|
||||
const I<T> &begin ();
|
||||
const I<T> &end ();
|
||||
private:
|
||||
I<T> b, e;
|
||||
};
|
||||
|
||||
template <typename T> const I<T> &J<T>::begin () { return b; }
|
||||
template <typename T> const I<T> &J<T>::end () { return e; }
|
||||
|
||||
static int f1count[3], f2count[3];
|
||||
|
||||
#ifndef __cplusplus
|
||||
extern void abort (void);
|
||||
#else
|
||||
extern "C" void abort (void);
|
||||
#endif
|
||||
|
||||
void f1 (int depth)
|
||||
{
|
||||
f1count[depth]++;
|
||||
}
|
||||
|
||||
void f2 (int depth)
|
||||
{
|
||||
f2count[depth]++;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void s1 (J<T> a1, J<T> a2, J<T> a3)
|
||||
{
|
||||
#pragma omp for collapse(3)
|
||||
for (auto i : a1)
|
||||
{
|
||||
f1 (0);
|
||||
for (auto j : a2)
|
||||
{
|
||||
f1 (1);
|
||||
for (auto k : a3)
|
||||
{
|
||||
f1 (2);
|
||||
f2 (2);
|
||||
}
|
||||
f2 (1);
|
||||
}
|
||||
f2 (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
int index[] = {0, 1, 2, 3, 4, 5};
|
||||
|
||||
J<int> x (&index[0], &index[3]);
|
||||
J<int> y (&index[0], &index[4]);
|
||||
J<int> z (&index[0], &index[5]);
|
||||
|
||||
f1count[0] = 0;
|
||||
f1count[1] = 0;
|
||||
f1count[2] = 0;
|
||||
f2count[0] = 0;
|
||||
f2count[1] = 0;
|
||||
f2count[2] = 0;
|
||||
|
||||
s1<int> (x, y, z);
|
||||
|
||||
/* All intervening code at the same depth must be executed the same
|
||||
number of times. */
|
||||
if (f1count[0] != f2count[0]) abort ();
|
||||
if (f1count[1] != f2count[1]) abort ();
|
||||
if (f1count[2] != f2count[2]) abort ();
|
||||
|
||||
/* Intervening code must be executed at least as many times as the loop
|
||||
that encloses it. */
|
||||
if (f1count[0] < 3) abort ();
|
||||
if (f1count[1] < 3 * 4) abort ();
|
||||
|
||||
/* Intervening code must not be executed more times than the number
|
||||
of logical iterations. */
|
||||
if (f1count[0] > 3 * 4 * 5) abort ();
|
||||
if (f1count[1] > 3 * 4 * 5) abort ();
|
||||
|
||||
/* Check that the innermost loop body is executed exactly the number
|
||||
of logical iterations expected. */
|
||||
if (f1count[2] != 3 * 4 * 5) abort ();
|
||||
}
|
Loading…
Add table
Reference in a new issue