On Tue, Apr 27, 2021 at 03:36:38PM +0200, Tobias Burnus wrote:
> OpenMP 5's iterator can be used for
> - depend clause
> - affinity clause
> - mapping (unsupported and not touched)
>
> (a) This patch add the iterator support to the Fortran FE
> and adds support for it to the depend clause.
>
> (b) It also adds a conforming stub implementation (parse & ignore in ME)
> for 'affinity' (Fortran, C, C++)
>
> (c) Fortran's taskwait did not handle the depend clause, now it does.
>
> The way the iterator is stored in Fortran is a bit convoluted,
> but should be fine:
> new namespace (such that symbols can be overridden and resolution works),
> using symbol->value for the iteration (begin:end:step) as array constructor,
> and abusing the ns->proc_name + its '->tlink' to generate an linked list,
> which avoids walking the ns->sym_root tree and has the user's order in
> the dump instead of the tree-walking order.
>
> The ME implementation also seems to require a very special way the
> variables are stored. – It seems as if it works correctly for depend;
> hence, I hope I did correctly read the dump and tree sharing is correctly
> handled.
>
> NOTE: The iterator Fortran patch includes one change from the post-OpenMP-5.0
> spec:
> The '::' after the typespec in order to avoid Fortran free-form source issues
> with:
Is the :: optional or required in free-form?
> 'iterator(integer i=1:10)' – namely: is this the integer 'i' or the variable
> 'integeri' (as spaces are ignored in fixed-form Fortran)?
> NOTE 2: The way it is implemented, the 'begin:end:step' expression is
> evaluated
> multiple times - once per list item; I think this matches C, but I am not
> completely
> sure nor whether that is a problem. (Unlikely a real-world problem.)
I believe C evaluates them just once and it would be nice if that could be
the case for Fortran too.
At least, looking at:
int bar (int);
void
foo (void)
{
int a[64];
#pragma omp task depend (iterator (j=bar(0):bar(1):bar(2)) , out : a[j])
;
}
I see all the bar calls just once:
saved_stack.6 = __builtin_stack_save ();
try
{
_1 = bar (0);
_2 = bar (1);
D.2078 = bar (2);
and never afterwards. So, it would be nice if Fortran could do the same,
wrap stuff in SAVE_EXPR or whatever is needed for that.
And even
void
qux (void)
{
int a[64], b[64], c[64];
#pragma omp task depend (iterator (j=bar(0):bar(1):bar(2)) , out : a[j], b[j],
c[j])
;
}
seems to evaluate just once.
> NOTE 3: I did have some trouble reading the spec with regards to what in C is
> permitted
> for 'affinity' ('locator-list); the code now mostly follows what is permitted
> for 'depend'.
locator-list is used for both affinity and depend, so I guess the same.
I think at least for the latter C/C++ arranges that by using the same
iterator tree for the adjacent vars, so that the middle-end knows it can
just evaluate it once and emit one loop instead of one loop for each
variable separately. Of course, depend (iterator (...),out : a[j])
depend(iterator (...),out : b[j])
will emit two different loops.
> @@ -15508,6 +15511,52 @@ c_parser_omp_iterators (c_parser *parser)
>return ret ? ret : error_mark_node;
> }
>
> +/* OpenMP 5.0:
> + affinity( [depend-modifier :] variable-list)
For consistency, I think the syntax for other clauses puts space
before ( and before ) too.
Also, s/depend-modifier/aff-modifier/
> + depend-modifier:
Likewise.
> + iterator ( iterators-definition ) */
> +
> +static tree
> +c_parser_omp_clause_affinity (c_parser *parser, tree list)
> +{
> + location_t clause_loc = c_parser_peek_token (parser)->location;
> + tree nl, iterators = NULL_TREE;
> +
> + matching_parens parens;
> + if (!parens.require_open (parser))
> +return list;
> +
> + if (c_parser_next_token_is (parser, CPP_NAME))
> +{
> + const char *p = IDENTIFIER_POINTER (c_parser_peek_token
> (parser)->value);
> + if (strcmp ("iterator", p) == 0)
> + {
> + iterators = c_parser_omp_iterators (parser);
> +if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
> + return list;
I think in this case it should
if (iterators)
pop_scope ();
parens.skip_until_found_close (parser);
before doing return list;
> + }
> +}
> + nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_AFFINITY,
> +list);
> + if (iterators)
> +{
> + tree block = pop_scope ();
> + if (iterators == error_mark_node)
> + iterators = NULL_TREE;
> + else
> + {
> + TREE_VEC_ELT (iterators, 5) = block;
> + for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
> + OMP_CLAUSE_DECL (c) = build_tree_list (iterators,
> +OMP_CLAUSE_DECL (c));
> + }
> +}
> +
> + parens.skip_until_found_close (parser);
> + return nl;
> +}
> +
> +
> @@ -14578,17 +14592,24 @@ c_finish_omp_clauses (tree clauses, enum
> c_omp_region_typ