https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120413

--- Comment #5 from Tobias Burnus <burnus at gcc dot gnu.org> ---
ICE FIXED so far for mainline (GCC 16) and GCC 15.

* * *

Reading:

> There is also BIND_EXPR_VARS, dunno if that should be walked instead
> or in addition.

The current code is about adding map clauses for lambda expressions,
excluding locally defined declarations:

—————————————————————————————————————————

/* Used to walk OpenMP target directive body.  */
struct omp_target_walk_data
{
  ...
  /* For lambda functions, the __closure object expression of the current
     function, and the set of captured variables accessed in target body.  */
  tree current_closure;
  hash_set<tree> closure_vars_accessed; 

  /* Local variables declared inside a BIND_EXPR, used to filter out such
     variables when recording lambda_objects_accessed.  */
  hash_set<tree> local_decls;
};

...

finish_omp_target_clauses_r (tree *tp, int *walk_subtrees, void *ptr)
{
...
  if (TREE_CODE (t) == BIND_EXPR)
    {
      if (tree block = BIND_EXPR_BLOCK (t))
        for (tree var = BLOCK_VARS (block); var; var = DECL_CHAIN (var))
          if (!data->local_decls.contains (var))
            data->local_decls.add (var);
#if 0  // To add?
        for (tree var = BIND_EXPR_VARS (t); var; var = DECL_CHAIN (var))
          if (!data->local_decls.contains (var))
            data->local_decls.add (var);
#endif
      return NULL_TREE;
    }

...

  if (TREE_TYPE (t) && LAMBDA_TYPE_P (TREE_TYPE (t)))
    {
...
      if (!data->lambda_objects_accessed.contains (t)
          /* Do not prepare to create target maps for locally declared
             lambdas or anonymous ones.  */
          && !data->local_decls.contains (t)
          && TREE_CODE (t) != TARGET_EXPR)
        data->lambda_objects_accessed.add (t);

...

  for (hash_set<tree>::iterator i = data.lambda_objects_accessed.begin ();
       i != data.lambda_objects_accessed.end (); ++i)
    {
...
      tree lc = build_omp_clause (loc, OMP_CLAUSE_MAP);
      OMP_CLAUSE_SET_MAP_KIND (lc, GOMP_MAP_TO);
      OMP_CLAUSE_DECL (lc) = lobj;
...
—————————————————————————————————————————


It seems that the only testcase for the current code is:

libgomp.c++/target-lambda-1.C
—————————————————————————————————————————
template <typename L>
void
omp_target_loop (int begin, int end, L loop)
{
  #pragma omp target teams distribute parallel for
  for (int i = begin; i < end; i++) 
    loop (i);
} 

...
  omp_target_loop (0, N, [=](int i) { data1[i] = val; });
  omp_target_loop (0, N, [=](int i) { data2[i] = valref + 1; });
—————————————————————————————————————————

Adding some warning diagnostic shows that during initial parsing:

   33 |               for (int i = 0; i < len; i++)

that both BIND_EXPR_BLOCK and BIND_EXPR_VARS contain 'i'.


Then for

libgomp.c++/target-lambda-1.C: In instantiation of ‘void omp_target_loop(int,
int, L) [with L = main()::<lambda(int)>]’:

(A) The same for 'i'.
(B) 'lambda_objects_accessed.add' for 'loop'.

And likewise for the other lambda.

=> In this case, BIND_EXPR_BLOCK and BIND_EXPR_VARS contain the same variable.


For the mapping, we get for the first call:

;; Function void omp_target_loop(int, int, L) [with L = main()::<lambda(int)>]
(null)

  #pragma omp target map(to:loop [len: 16])  map(alloc:*loop.__data1 [len: 0])
\
                     map(attach_zero_length_array_section:loop.__data1 [bias:
0])

with

  int * const data1 [value-expr: __closure->__data1];
  const int val [value-expr: __closure->__val];

* * *

It looks as if BIND_EXPR is primarily created via c-family/c-gimplify.cc's

  tree decls, bind;

  if (block == NULL_TREE)
    decls = NULL_TREE;
  else if (TREE_CODE (block) == BLOCK)
    decls = BLOCK_VARS (block);
  else
    {
      decls = block;
...
  if (decls || block)
    {
      bind = build3 (BIND_EXPR, void_type_node, decls, body, block);

such that walking BLOCK_VARS shouldn't be required.

Only other use with decl != NULL:

cp/init.cc:4214:  controller = build3 (BIND_EXPR, void_type_node, tbase,
NULL_TREE, NULL_TREE);

* * *

→ Hence, IMHO, the current code is fine – as would be using BLOCK_VARS.

Reply via email to