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

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jakub at gcc dot gnu.org

--- Comment #24 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Completely untested routine that would allow unsharing expressions including
SAVE_EXPRs/TARGET_EXPRs, obviously then the result couldn't be used in the IL
for code generation, only for warnings.
It is basically unshare_expr, which afterwards when it sees SAVE_EXPRs or
TARGET_EXPRs
for the first time copies those and unshares their subtrees and when it sees
those
second and following time just reuses what it did before.

/* Helper function for fully_unshare_expr.  Copy SAVE_EXPRs and TARGET_EXPRs
   including their subtrees, but do that only once.  */

static tree
fully_unshare_expr_r (tree *tp, int *walk_subtrees, void *data)
{
  enum tree_code code = TREE_CODE (*tp);
  if (code == SAVE_EXPR || code == TARGET_EXPR)
    {
      hash_map<tree, tree> **map = (hash_map<tree, tree> **) data;
      *walk_subtrees = 0;
      if (*map == NULL)
        *map = new hash_map<tree, tree>;
      tree &cached = (*map)->get_or_insert (*tp);
      if (cached)
        {
          *tp = cached;
          return NULL_TREE;
        }
      tree t = copy_node (*tp);
      cached = t;
      int len = 1;
      if (code == TARGET_EXPR)
        len = (TREE_OPERAND (t, 3) == TREE_OPERAND (t, 1)) ? 3 : 4;
      for (int i = 0; i < len; i++)
        {
          TREE_OPERAND (t, i) = unshare_expr (TREE_OPERAND (t, i));
          walk_tree (&TREE_OPERAND (t, i), fully_unshare_expr_r, data, NULL);
        }
      if (len == 3)
        TREE_OPERAND (t, 3) = TREE_OPERAND (t, 1);
      return NULL_TREE;
    }
  /* Stop at types, decls, constants like copy_tree_r.  */
  else if (TREE_CODE_CLASS (code) == tcc_type
           || TREE_CODE_CLASS (code) == tcc_declaration
           || TREE_CODE_CLASS (code) == tcc_constant)
    *walk_subtrees = 0;
  return NULL_TREE;
}

/* Like unshare_expr, but unshare also SAVE_EXPRs and TARGET_EXPRs.
   After unsharing SAVE_EXPRs and TARGET_EXPRs, the returned expression
   shouldn't be gimplified into the IL, as that could mean evaluating
   side-effects multiple times.  */

tree
fully_unshare_expr (tree expr)
{
  hash_map <tree, tree> *map = NULL;
  expr = unshare_expr (expr);
  walk_tree (&expr, fully_unshare_expr_r, &map, NULL);
  delete map;
  return expr;
}

Reply via email to