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:
Sandra Loosemore 2023-08-24 17:35:00 +00:00
parent 143151ac20
commit 53891f18f3
27 changed files with 3239 additions and 419 deletions

View file

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

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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)
{

View file

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

View file

@ -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++)

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

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

View file

@ -11,7 +11,7 @@ foo ()
{
for (int j = 0; j < 5; ++j)
++sum;
++sum; // { dg-error "collapsed loops not perfectly nested" }
++sum;
}
return sum;
}

View 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> ();
}

View 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> ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}

View 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 ();
}