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

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

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

--- Comment #6 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Jozef Lawrynowicz from comment #5)
> (In reply to Richard Biener from comment #4)
> 
> Thanks for the pointers.
> 
> > What happens if you make the attribute work for a MODE_INT union with a
> > MODE_PARTIAL_INT first field that has MODE_SIZE of the union mode?
> >
> > Is there
> > a generic way to query SImode for PSImode as defined in
> > 
> > PARTIAL_INT_MODE (SI, 20, PSI);
> > 
> > ?  Or does one need to compare MODE_SIZE?
> 
> I believe you just have to compare MODE_SIZE as I did below.
> 
> >  Can there be multiple non-partial integer modes with the same size?
> 
> Currently for the targets using PARTIAL_INT_MODE there is only a one-to-one
> mapping from the "full" mode to the partial mode. But where it can get
> tricky is when examining the BITSIZE of a partial int mode, as depending on
> the context, the bitsize could be the bitsize of the SI mode or the true
> bitsize of the PSImode i.e. the precision.
> 
> I tried this (there may well be a neater way):
> 
> diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
> index 4416b50..74f6a76 100644
> --- a/gcc/c-family/c-attribs.c
> +++ b/gcc/c-family/c-attribs.c
> @@ -1280,7 +1280,11 @@ handle_transparent_union_attribute (tree *node, tree
> name,
>           tree first = first_field (type);
>           if (first == NULL_TREE
>               || DECL_ARTIFICIAL (first)
> -             || TYPE_MODE (type) != DECL_MODE (first))
> +             || (TYPE_MODE (type) != DECL_MODE (first)
> +                 && !(GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
> +                      && GET_MODE_CLASS (DECL_MODE(first)) ==
> MODE_PARTIAL_INT
> +                      && known_eq (GET_MODE_BITSIZE (TYPE_MODE (type)),
> +                                   GET_MODE_BITSIZE (DECL_MODE (first))))))
>             goto ignored;
>         }
> 
> It fixes most of those failing DejaGNU tests, except pr34885.c ends up
> ICE-ing at "-O3 -g".
> 
> during RTL pass: final^M
> /home/jozef/msp430/gcc/gcc/testsuite/gcc.c-torture/compile/pr34885.c: In
> function 'send':^M
> /home/jozef/msp430/gcc/gcc/testsuite/gcc.c-torture/compile/pr34885.c:9:1:
> internal compiler error: Segmentation fault^M
> 0xb58f4f crash_signal^M
>   ../../gcc/toplev.c:325^M
> 0x7bf92d gen_subprogram_die^M
>   ../../gcc/dwarf2out.c:23270^M
> 0x7c1c5b gen_decl_die^M
>   ../../gcc/dwarf2out.c:26197^M
> 0x7c3f9e dwarf2out_decl^M
>   ../../gcc/dwarf2out.c:26765^M
> 0x7d707e dwarf2out_function_decl^M
>   ../../gcc/dwarf2out.c:26780^M
> 0x83e757 rest_of_handle_final^M
>   ../../gcc/final.c:4681^M
> 0x83e757 execute^M
>   ../../gcc/final.c:4723^M
> 
> I haven't investigated the above ICE as the below alternative approach fixes
> the issue and offers codegen benefits.
> 
> diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
> index 58a3aa3..6449f16 100644
> --- a/gcc/stor-layout.c
> +++ b/gcc/stor-layout.c
> @@ -1844,10 +1844,15 @@ compute_record_mode (tree type)
>      }
>  
>    /* If we only have one real field; use its mode if that mode's size
> -     matches the type's size.  This only applies to RECORD_TYPE.  This
> -     does not apply to unions.  */
> +     matches the type's size.  This generally only applies to RECORD_TYPE.
> +     As an exception, if the union will be passed by reference then it is
> +     acceptable to use the mode of the widest field for the mode of the
> +     union.  */
>    poly_uint64 type_size;
> -  if (TREE_CODE (type) == RECORD_TYPE
> +  if (((TREE_CODE (type) == RECORD_TYPE)
> +       || (TREE_CODE (type) == UNION_TYPE
> +          && targetm.calls.pass_by_reference (pack_cumulative_args (NULL),
> +                                              mode, type, 0)))
>        && mode != VOIDmode
>        && poly_int_tree_p (TYPE_SIZE (type), &type_size)
>        && known_eq (GET_MODE_BITSIZE (mode), type_size))
> 
> The codegen benefits are that the target might have instructions to
> specifically operate on the partial int mode, which it can use if the mode
> of the union is set to this partial int mode.
> 
> So for msp430 if the widest type in a union is __int20 (PSImode), then
> allowing the union mode to be PSImode results in fewer instructions being
> used to manipulate the union, compared to if the union mode was SImode.
> 
> I'll go ahead and test the second patch, unless there is a reason not to
> allow non-MODE_INT unions. If, for example, we'd rather not have unions be
> MODE_FLOAT I could always restrict the above logic further to only allow the
> union mode to be set to a MODE_PARTIAL_INT in addition to the currently
> allowable MODE_INT.

I think it's better to, at this place, simply allow MODE_INT or
MODE_PARTIAL_INT
for unions.  Allowing MODE_INT is what we'd fall back to anyways and you
want to allow MODE_PARTIAL_INT which is already allowed for RECORD_TYPEs.

What I'm not sure is if the target is happy about, say,

union U { float f; __int20 i; };

float foo()
{
  union U u;
  u.i = 10;
  return u.f;
}

iff we were to put u into a MODE_PARTIAL_INT register are targets to be
expected to be able to extract a MODE_FLOAT from it or are we going
to spill here anyways?

How is TYPE_SIZE / GET_MODE_BITSIZE of this union anyways?  The loop
in stor-layout checks TYPE_SIZE vs. DECL_SIZE - is DECL_SIZE always
matching GET_MODE_BITSIZE?

Reply via email to