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

Richard Biener <rguenth at gcc dot gnu.org> changed:

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

--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> ---
The interesting thing is that the RHS _1 is from a different function, a
SAVE_EXPR expansion actually, which means this is another case of
cross-function
tree sharing (I remember fixing such thing in the fortran FE).

Breakpoint 7, gimplify_save_expr (expr_p=0x7ffff6db3b18, pre_p=0x7fffffffd058, 
    post_p=0x7fffffffca98) at ../../src/trunk/gcc/gimplify.c:5870
5870      enum gimplify_status ret = GS_ALL_DONE;
$38 = <save_expr 0x7ffff6da3a80>
$39 = <function_decl 0x7ffff6dac100 b>
...
Breakpoint 7, gimplify_save_expr (expr_p=0x7ffff6da3ab8, pre_p=0x7fffffffc658, 
    post_p=0x7fffffffc458) at ../../src/trunk/gcc/gimplify.c:5870
5870      enum gimplify_status ret = GS_ALL_DONE;
$42 = <save_expr 0x7ffff6da3a80>
$43 = <function_decl 0x7ffff6dac400 operator()>
(gdb) p (*expr_p)->base.public_flag 
$45 = 1

I guess we can track down at least the SAVE_EXPR case with

Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c      (revision 262624)
+++ gcc/gimplify.c      (working copy)
@@ -869,7 +869,11 @@ copy_if_shared_r (tree *tp, int *walk_su

   /* Otherwise, mark the node as visited and keep looking.  */
   else
-    TREE_VISITED (t) = 1;
+    {
+      if (TREE_CODE (t) == SAVE_EXPR)
+       gcc_assert (!SAVE_EXPR_RESOLVED_P (t));
+      TREE_VISITED (t) = 1;
+    }

   return NULL_TREE;
 }


It's probably easy that this case of sharing happens for nested functions
since most type sizes are wrapped in SAVE_EXPRs and those do not get
unshared even when that is explicitely asked for.

But it looks like the tree sharing happens outside of a SAVE_EXPR given
we have at gimplify_function_tree time

{
  intptr_t & n [value-expr: this->__n];

    intptr_t & n [value-expr: this->__n];
  {
    <<cleanup_point <<< Unknown tree: expr_stmt
  (void) (*n = (intptr_t) ((unsigned int) (_1 + 1) * 4)) >>>>>;
  }
}

where _1 + 1 was what a SAVE_EXPR was resolved to but here we should have
seen the DECL created for it rather than the in-place gimplified result.

The .original dump though has

;; Function b(intptr_t, T) [with T = int; intptr_t =
int]::<lambda()>::<lambda()> (null)
;; enabled by -tree-original


{
  intptr_t & n [value-expr: this->__n];

    intptr_t & n [value-expr: this->__n];
  {
    <<cleanup_point <<< Unknown tree: expr_stmt
  (void) (*n = (intptr_t) ((unsigned int) ((sizetype) (SAVE_EXPR <(ssizetype)
arg + -1>) + 1) * 4)) >>>>>;
  }
}

it looks like there's tree sharing for a bigger part of the expression...

Indeed, between the above and

{
  intptr_t & n [value-expr: this->__n];

    intptr_t & n [value-expr: this->__n];
  {
    {
      typedef struct __lambda3 __lambda3;

      <<cleanup_point <<< Unknown tree: expr_stmt
  (void) (*n = (intptr_t) ((unsigned int) ((sizetype) (SAVE_EXPR <(ssizetype)
arg + -1>) + 1) * 4)) >>>>>;
      <<cleanup_point <<< Unknown tree: expr_stmt
  b(intptr_t, T) [with T = int; intptr_t =
int]::<lambda()>::<lambda()>::operator() (&TARGET_EXPR <D.2347, {.__n=n}>)
>>>>>;
    }
  }
}

we have shared

                arg:0 <plus_expr 0x7ffff6dae140 type <integer_type
0x7ffff6c5b000 sizetype>
                    side-effects
                    arg:0 <nop_expr 0x7ffff6da3aa0 type <integer_type
0x7ffff6c5b000 sizetype>
                        side-effects
                        arg:0 <save_expr 0x7ffff6da3a80 type <integer_type
0x7ffff6c5b150 ssizetype>
                            side-effects arg:0 <plus_expr 0x7ffff6daee60>
                            t.ii:3:22 start: t.ii:3:22 finish: t.ii:3:26>>
                    arg:1 <integer_cst 0x7ffff6c3df78 constant 1>>>

which is the (sizetype) (SAVE_EXPR <(ssizetype) arg + -1>) + 1 part.

 <nop_expr 0x7ffff6db30e0
vs.
 <nop_expr 0x7ffff6da3e00
    type <integer_type 0x7ffff6c5b7e0 long unsigned int public unsigned DI
        size <integer_cst 0x7ffff6c3de70 constant 64>
        unit-size <integer_cst 0x7ffff6c3de88 constant 8>
        align:64 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type
0x7ffff6c5b7e0 precision:64 min <integer_cst 0x7ffff6c5e150 0> max <integer_cst
0x7ffff6c3e5c0 18446744073709551615>
        pointer_to_this <pointer_type 0x7ffff6c6b498>>
    side-effects
    arg:0 <mult_expr 0x7ffff6dae168
        type <integer_type 0x7ffff6c5b000 sizetype public unsigned DI size
<integer_cst 0x7ffff6c3de70 64> unit-size <integer_cst 0x7ffff6c3de88 8>
            align:64 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type
0x7ffff6c5b000 precision:64 min <integer_cst 0x7ffff6c3dea0 0> max <integer_cst
0x7ffff6c3e560 18446744073709551615>>
        side-effects
        arg:0 <plus_expr 0x7ffff6dae140 type <integer_type 0x7ffff6c5b000
sizetype>
            side-effects

these nodes are built by c_sizeof_or_alignof_type

#4  0x0000000000bde3e2 in c_sizeof_or_alignof_type (loc=283249, 
    type=<array_type 0x7ffff6da95e8 ArrTy>, is_sizeof=true, min_alignof=false, 
    complain=1) at ../../src/trunk/gcc/c-family/c-common.c:3650
3650      value = fold_convert_loc (loc, size_type_node, value);

where TYPE_SIZE_UNIT of type is

((sizetype) (SAVE_EXPR <(ssizetype) arg - 1>) + 1) * 4

which is of course asking for trouble :/

In the end this is layout_type doing

2483                if (TYPE_SIZE_UNIT (element))
2484                  TYPE_SIZE_UNIT (type)
2485                    = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (element),
length);

on (sizetype) (SAVE_EXPR <(ssizetype) arg - 1>) + 1

The gimplifier is not set up to do unsharing across functions, so this has
to be fixed elsewhere.  The particular case could be fixed in
c_sizeof_or_alignof_type by doing unshare_expr on TYPE_SIZE_UNIT for all
types that might be shared between functions (thus where the gimplifier
doesn't take care of unsharing).

Or we could make layout_type make sure to wrap all non-constant TYPE_*
in a SAVE_EXPR.

So the following patch restores the ICE we see in earlier releases.
I have audited all possibly variable-size processing in c-common.c.

Any comments?

Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c     (revision 262624)
+++ gcc/c-family/c-common.c     (working copy)
@@ -3635,7 +3635,8 @@ c_sizeof_or_alignof_type (location_t loc
     {
       if (is_sizeof)
        /* Convert in case a char is more than one unit.  */
-       value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
+       value = size_binop_loc (loc, CEIL_DIV_EXPR,
+                               unshare_expr (TYPE_SIZE_UNIT (type)),
                                size_int (TYPE_PRECISION (char_type_node)
                                          / BITS_PER_UNIT));
       else if (min_alignof)
@@ -6210,7 +6211,8 @@ fold_offsetof (tree expr, tree type, enu
                 "member %qD", t);
          return error_mark_node;
        }
-      off = size_binop_loc (input_location, PLUS_EXPR, DECL_FIELD_OFFSET (t),
+      off = size_binop_loc (input_location, PLUS_EXPR,
+                           unshare_expr (DECL_FIELD_OFFSET (t)),
                            size_int (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (t))
                                      / BITS_PER_UNIT));
       break;
@@ -6266,7 +6268,8 @@ fold_offsetof (tree expr, tree type, enu
        }

       t = convert (sizetype, t);
-      off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
+      off = size_binop (MULT_EXPR,
+                       unshare_expr (TYPE_SIZE_UNIT (TREE_TYPE (expr))), t);
       break;

     case COMPOUND_EXPR:

Reply via email to