Hi! The FE guarantees that the iterator type the middle-end sees is either some integral type, or pointer type. For taskloop, we need to pass around (firstprivatize) the b and lb expressions if they aren't simple constants, but unfortunately for the middle-end reference vs. pointer type differences are considered useless, so when we gimplify (int *) x where int &x, we can end up with a temporary that has int & type. That matters for firstprivate clause though, int * is firstprivatized by copying the pointer, while int & is firstprivatized by adding an int temporary, initializing that temporary from the orig reference and initializing the new private reference to the address of the int temporary.
So, the following code ensures that the temporary we firstprivatize has the right type. Bootstrapped/regtested on x86_64-linux and i686-linux, queued for backporting. 2018-07-17 Jakub Jelinek <ja...@redhat.com> PR middle-end/86539 * gimplify.c (gimplify_omp_for): Ensure taskloop firstprivatized init and cond temporaries don't have reference type if iterator has pointer type. For init use &for_pre_body instead of pre_p if for_pre_body is non-empty. * testsuite/libgomp.c++/pr86539.C: New test. --- gcc/gimplify.c.jj 2018-07-10 09:11:24.251062149 +0200 +++ gcc/gimplify.c 2018-07-16 19:10:25.386498090 +0200 @@ -9811,9 +9811,26 @@ gimplify_omp_for (tree *expr_p, gimple_s t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i); if (!is_gimple_constant (TREE_OPERAND (t, 1))) { + tree type = TREE_TYPE (TREE_OPERAND (t, 0)); TREE_OPERAND (t, 1) = get_initialized_tmp_var (TREE_OPERAND (t, 1), - pre_p, NULL, false); + gimple_seq_empty_p (for_pre_body) + ? pre_p : &for_pre_body, NULL, + false); + /* Reference to pointer conversion is considered useless, + but is significant for firstprivate clause. Force it + here. */ + if (TREE_CODE (type) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 1))) + == REFERENCE_TYPE)) + { + tree v = create_tmp_var (TYPE_MAIN_VARIANT (type)); + tree m = build2 (INIT_EXPR, TREE_TYPE (v), v, + TREE_OPERAND (t, 1)); + gimplify_and_add (m, gimple_seq_empty_p (for_pre_body) + ? pre_p : &for_pre_body); + TREE_OPERAND (t, 1) = v; + } tree c = build_omp_clause (input_location, OMP_CLAUSE_FIRSTPRIVATE); OMP_CLAUSE_DECL (c) = TREE_OPERAND (t, 1); @@ -9825,11 +9842,26 @@ gimplify_omp_for (tree *expr_p, gimple_s t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), i); if (!is_gimple_constant (TREE_OPERAND (t, 1))) { + tree type = TREE_TYPE (TREE_OPERAND (t, 0)); TREE_OPERAND (t, 1) = get_initialized_tmp_var (TREE_OPERAND (t, 1), gimple_seq_empty_p (for_pre_body) ? pre_p : &for_pre_body, NULL, false); + /* Reference to pointer conversion is considered useless, + but is significant for firstprivate clause. Force it + here. */ + if (TREE_CODE (type) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 1))) + == REFERENCE_TYPE)) + { + tree v = create_tmp_var (TYPE_MAIN_VARIANT (type)); + tree m = build2 (INIT_EXPR, TREE_TYPE (v), v, + TREE_OPERAND (t, 1)); + gimplify_and_add (m, gimple_seq_empty_p (for_pre_body) + ? pre_p : &for_pre_body); + TREE_OPERAND (t, 1) = v; + } tree c = build_omp_clause (input_location, OMP_CLAUSE_FIRSTPRIVATE); OMP_CLAUSE_DECL (c) = TREE_OPERAND (t, 1); --- libgomp/testsuite/libgomp.c++/pr86539.C.jj 2018-07-16 18:56:40.491472344 +0200 +++ libgomp/testsuite/libgomp.c++/pr86539.C 2018-07-16 18:56:34.068464199 +0200 @@ -0,0 +1,28 @@ +// PR middle-end/86539 + +int a[384]; + +__attribute__((noipa)) void +foo (int &b, int &c) +{ + #pragma omp taskloop shared (a) collapse(3) + for (int i = 0; i < 1; i++) + for (int *p = &b; p < &c; p++) + for (int j = 0; j < 1; j++) + if (p < &a[128] || p >= &a[256]) + __builtin_abort (); + else + p[0]++; +} + +int +main () +{ + #pragma omp parallel + #pragma omp single + foo (a[128], a[256]); + for (int i = 0; i < 384; i++) + if (a[i] != (i >= 128 && i < 256)) + __builtin_abort (); + return 0; +} Jakub