This part is also in omp-low.c.

We scan and adjust the code during omp-lowering, to add the biases for each 
dimension when
a dynamic array access is detected, which is required for generally supporting 
copying
sections of each dimension.

The code is a bit sophisticated, and I wonder if this is better implemented in 
gimplify.c
(though probably a non-trivial task as well). Nevertheless, it is currently 
working.

Thanks,
Chung-Lin

        gcc/
        * omp-low.c (dynamic_array_lookup): New function.
        (dynamic_array_reference_start): Likewise.
        (scan_for_op): Likewise.
        (scan_for_reference): Likewise.
        (da_create_bias): Likewise.
        (da_dimension_peel): Likewise.
        (lower_omp_1): Add case to look for start of dynamic array reference,
        and handle bias adjustments for the code sequence.
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 6a1cb05..4c44800 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -8734,6 +8946,201 @@ lower_omp_grid_body (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
                       gimple_build_omp_return (false));
 }
 
+/* Helper to lookup dynamic array through nested omp contexts. Returns
+   TREE_LIST of dimensions, and the CTX where it was found in *CTX_P.  */
+
+static tree
+dynamic_array_lookup (tree t, omp_context **ctx_p)
+{
+  omp_context *c = *ctx_p;
+  while (c)
+    {
+      tree *dims = c->dynamic_arrays->get (t);
+      if (dims)
+       {
+         *ctx_p = c;
+         return *dims;
+       }
+      c = c->outer;
+    }
+  return NULL_TREE;
+}
+
+/* Tests if this gimple STMT is the start of a dynamic array access sequence.
+   Returns true if found, and also returns the gimple operand ptr and
+   dimensions tree list through *OUT_REF and *OUT_DIMS respectively.  */
+
+static bool
+dynamic_array_reference_start (gimple *stmt, omp_context **ctx_p,
+                              tree **out_ref, tree *out_dims)
+{
+  if (gimple_code (stmt) == GIMPLE_ASSIGN)
+    for (unsigned i = 1; i < gimple_num_ops (stmt); i++)
+      {
+       tree *op = gimple_op_ptr (stmt, i), dims;
+       if (TREE_CODE (*op) == ARRAY_REF)
+         op = &TREE_OPERAND (*op, 0);
+       if (TREE_CODE (*op) == MEM_REF)
+         op = &TREE_OPERAND (*op, 0);
+       if ((dims = dynamic_array_lookup (*op, ctx_p)) != NULL_TREE)
+         {
+           *out_ref = op;
+           *out_dims = dims;
+           return true;
+         }
+      }
+  return false;
+}
+
+static tree
+scan_for_op (tree *tp, int *walk_subtrees, void *data)
+{
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+  tree t = *tp;
+  tree op = (tree) wi->info;
+  *walk_subtrees = 1;
+  if (operand_equal_p (t, op, 0))
+    {
+      wi->info = tp;
+      return t;
+    }
+  return NULL_TREE;
+}
+
+static tree *
+scan_for_reference (gimple *stmt, tree op)
+{
+  struct walk_stmt_info wi;
+  memset (&wi, 0, sizeof (wi));
+  wi.info = op;
+  if (walk_gimple_op (stmt, scan_for_op, &wi))
+    return (tree *) wi.info;
+  return NULL;
+}
+
+static tree
+da_create_bias (tree orig_bias, tree unit_type)
+{
+  return build2 (MULT_EXPR, sizetype, fold_convert (sizetype, orig_bias),
+                TYPE_SIZE_UNIT (unit_type));
+}
+
+/* Main worker for adjusting dynamic array accesses, handles the adjustment
+   of many cases of statement forms, and called multiple times to 'peel' away
+   each dimension.  */
+
+static gimple_stmt_iterator
+da_dimension_peel (omp_context *da_ctx,
+                  gimple_stmt_iterator da_gsi, tree orig_da,
+                  tree *da_op_p, tree *da_type_p, tree *da_dims_p)
+{
+  gimple *stmt = gsi_stmt (da_gsi);
+  tree lhs = gimple_assign_lhs (stmt);
+  tree rhs = gimple_assign_rhs1 (stmt);
+
+  if (gimple_num_ops (stmt) == 2
+      && TREE_CODE (rhs) == MEM_REF
+      && operand_equal_p (*da_op_p, TREE_OPERAND (rhs, 0), 0)
+      && !operand_equal_p (orig_da, TREE_OPERAND (rhs, 0), 0)
+      && (TREE_OPERAND (rhs, 1) == NULL_TREE
+         || integer_zerop (TREE_OPERAND (rhs, 1))))
+    {
+      gcc_assert (TREE_CODE (TREE_TYPE (*da_type_p)) == POINTER_TYPE);
+      *da_type_p = TREE_TYPE (*da_type_p);
+    }
+  else 
+    {
+      gimple *g;
+      gimple_seq ilist = NULL;
+      tree bias, t;
+      tree op = *da_op_p;
+      tree orig_type = *da_type_p;
+      tree orig_bias = TREE_PURPOSE (*da_dims_p);
+      bool by_ref = false;
+
+      if (TREE_CODE (orig_bias) != INTEGER_CST)
+       orig_bias = lookup_decl (orig_bias, da_ctx);
+
+      if (gimple_num_ops (stmt) == 2)
+       {
+         if (TREE_CODE (rhs) == ADDR_EXPR)
+           {
+             rhs = TREE_OPERAND (rhs, 0);
+             *da_dims_p = NULL_TREE;
+           }
+
+         if (TREE_CODE (rhs) == ARRAY_REF
+             && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
+             && operand_equal_p (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0),
+                                 *da_op_p, 0))
+           {
+             bias = da_create_bias (orig_bias,
+                                    TREE_TYPE (TREE_TYPE (orig_type)));
+             *da_type_p = TREE_TYPE (TREE_TYPE (orig_type));
+           }
+         else if (TREE_CODE (rhs) == ARRAY_REF
+                  && TREE_CODE (TREE_OPERAND (rhs, 0)) == VAR_DECL
+                  && operand_equal_p (TREE_OPERAND (rhs, 0), *da_op_p, 0))
+           {
+             tree ptr_type = build_pointer_type (orig_type);
+             op = create_tmp_var (ptr_type);
+             gimplify_assign (op, build_fold_addr_expr (TREE_OPERAND (rhs, 0)),
+                              &ilist);
+             bias = da_create_bias (orig_bias, TREE_TYPE (orig_type));
+             *da_type_p = TREE_TYPE (orig_type);
+             orig_type = ptr_type;
+             by_ref = true;
+           }
+         else if (TREE_CODE (rhs) == MEM_REF
+                  && operand_equal_p (*da_op_p, TREE_OPERAND (rhs, 0), 0)
+                  && TREE_OPERAND (rhs, 1) != NULL_TREE)
+           {
+             bias = da_create_bias (orig_bias, TREE_TYPE (orig_type));
+             *da_type_p = TREE_TYPE (orig_type);
+           }
+         else if (TREE_CODE (lhs) == MEM_REF
+                  && operand_equal_p (*da_op_p, TREE_OPERAND (lhs, 0), 0))
+           {
+             if (*da_dims_p != NULL_TREE)
+               {
+                 gcc_assert (TREE_CHAIN (*da_dims_p) == NULL_TREE);
+                 bias = da_create_bias (orig_bias, TREE_TYPE (orig_type));
+                 *da_type_p = TREE_TYPE (orig_type);
+               }
+             else
+               /* This should be the end of the dynamic array access
+                  sequence.  */
+               return da_gsi;
+           }
+         else
+           gcc_unreachable ();
+       }
+      else if (gimple_num_ops (stmt) == 3
+              && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
+              && operand_equal_p (*da_op_p, rhs, 0))
+       {
+         bias = da_create_bias (orig_bias, TREE_TYPE (orig_type));
+       }
+      else
+       gcc_unreachable ();
+
+      bias = fold_build1 (NEGATE_EXPR, sizetype, bias);
+      bias = fold_build2 (POINTER_PLUS_EXPR, orig_type, op, bias);
+
+      t = create_tmp_var (by_ref ? build_pointer_type (orig_type) : orig_type);
+
+      g = gimplify_assign (t, bias, &ilist);
+      gsi_insert_seq_before (&da_gsi, ilist, GSI_NEW_STMT);
+      *da_op_p = gimple_assign_lhs (g);
+
+      if (by_ref)
+       *da_op_p = build2 (MEM_REF, TREE_TYPE (orig_type), *da_op_p,
+                          build_int_cst (orig_type, 0));
+      *da_dims_p = TREE_CHAIN (*da_dims_p);
+    }
+
+  return da_gsi;
+}
 
 /* Callback for lower_omp_1.  Return non-NULL if *tp needs to be
    regimplified.  If DATA is non-NULL, lower_omp_1 is outside
@@ -9009,6 +9416,51 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context 
*ctx)
          }
       /* FALLTHRU */
     default:
+
+      /* If we detect the start of a dynamic array reference sequence, scan
+        and do the needed adjustments.  */
+      tree da_dims, *da_op_p;
+      omp_context *da_ctx = ctx;
+      if (da_ctx && dynamic_array_reference_start (stmt, &da_ctx,
+                                                  &da_op_p, &da_dims))
+       {
+         bool started = false;
+         tree orig_da = *da_op_p;
+         tree da_type = TREE_TYPE (orig_da);
+         tree next_da_op;
+
+         gimple_stmt_iterator da_gsi = *gsi_p, new_gsi;
+         while (da_op_p)
+           {
+             if (!is_gimple_assign (gsi_stmt (da_gsi))
+                 || ((gimple_assign_single_p (gsi_stmt (da_gsi))
+                      || gimple_assign_cast_p (gsi_stmt (da_gsi)))
+                     && *da_op_p == gimple_assign_rhs1 (gsi_stmt (da_gsi))))
+               break;
+
+             new_gsi = da_dimension_peel (da_ctx, da_gsi, orig_da,
+                                          da_op_p, &da_type, &da_dims);
+             if (!started)
+               {
+                 /* Point 'stmt' to the start of the newly added
+                    sequence.  */
+                 started = true;
+                 *gsi_p = new_gsi;
+                 stmt = gsi_stmt (*gsi_p);
+               }
+             if (!da_dims)
+               break;
+
+             next_da_op = gimple_assign_lhs (gsi_stmt (da_gsi));
+
+             do {
+               gsi_next (&da_gsi);
+               da_op_p = scan_for_reference (gsi_stmt (da_gsi), next_da_op);
+             }
+             while (!da_op_p);
+           }
+       }
+
       if ((ctx || task_shared_vars)
          && walk_gimple_op (stmt, lower_omp_regimplify_p,
                             ctx ? NULL : &wi))

Reply via email to