On Tue, 1 Mar 2016, Alan Modra wrote:

> This patch cures a problem with ICF of read-only variables at the
> intersection of -fsection-anchors, -ftree-loop-vectorize, and targets
> with alignment restrictions.  The testcase results in
> /usr/local/powerpc64le-linux/bin/ld: pack.o: In function `main':
> pack.c:(.text.startup+0xc): error: R_PPC64_TOC16_LO_DS not a multiple of 4
> /usr/local/powerpc64le-linux/bin/ld: final link failed: Bad value
> on powerpc64le-linux.
> 
> What happens is:
> - "c" is referenced in a constructor, thus make_decl_rtl for "c",
> - make_decl_rtl puts "c" in an anchor block (-fsection-anchors),
> - anchor block contents can't move, so "c" alignment can't change by
>   ipa_increase_alignment (-ftree-loop-vectorize),
> - however "a" alignment can be increased,
> - ICF aliases "a" to "c".
> So we have a decl for "a" saying it is aligned to 128 bits, using mem
> for "c" which is only 16 bit aligned.  The supposed increased
> alignment causes "a" to be accessed as a 64-bit word, and the
> powerpc64 backend to use a ds-form addressing mode.
> 
> Somewhere this chain of events needs to be broken.  It isn't possible
> to stop ipa_increase_alignment changing "a", because at that stage
> ICF aliases don't exist.  So it seemed to me that ICF needed to be
> taught not to create a problematic alias.  Not being very familiar
> with this code, I don't know if the following is the best place to
> change, but sem_variable::merge does throw away aliases for quite a
> lot of other reasons.  Another possibility is
> sem_variable::equals_wpa, where there's a comment about DECL_ALIGN
> being safe to merge "because we will always choose the largest
> alignment out of all aliases".  Except with this testcase we don't
> choose the largest alignment, and indeed can't (I think) due to "c"
> being used in a constructor.
> 
> Bootstrapped and regression tested powerpc64le-linux.  OK to apply?

Ok.

Thanks,
Richard.

> gcc/
>       PR ipa/69990
>       * ipa-icf.c (sem_variable::merge): Do not merge an alias with
>       larger alignment.
> gcc/testsuite/
>       gcc.dg/pr69990.c: New.
> 
> diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
> index ef04c55..d82eb87 100644
> --- a/gcc/ipa-icf.c
> +++ b/gcc/ipa-icf.c
> @@ -2209,6 +2209,16 @@ sem_variable::merge (sem_item *alias_item)
>                "adress of original and alias may be compared.\n\n");
>        return false;
>      }
> +
> +  if (DECL_ALIGN (original->decl) < DECL_ALIGN (alias->decl))
> +    {
> +      if (dump_file)
> +     fprintf (dump_file, "Not unifying; "
> +              "original and alias have incompatible alignments\n\n");
> +
> +      return false;
> +    }
> +
>    if (DECL_COMDAT_GROUP (original->decl) != DECL_COMDAT_GROUP (alias->decl))
>      {
>        if (dump_file)
> diff --git a/gcc/testsuite/gcc.dg/pr69990.c b/gcc/testsuite/gcc.dg/pr69990.c
> new file mode 100644
> index 0000000..efb835e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr69990.c
> @@ -0,0 +1,24 @@
> +/* { dg-do run } */
> +/* { dg-require-effective-target section_anchors } */
> +/* { dg-options "-O2 -fsection-anchors -ftree-loop-vectorize" } */
> +
> +#pragma pack(1)
> +struct S0 {
> +  volatile int f0:12;
> +} static a[] = {{15}}, c[] = {{15}};
> +
> +struct S0 b[] = {{7}};
> +
> +int __attribute__ ((noinline, noclone))
> +ok (int a, int b, int c)
> +{
> +  return a == 15 && b == 7 && c == 15 ? 0 : 1;
> +}
> +
> +int
> +main (void)
> +{
> +  struct S0 *f[] = { c, b };
> +
> +  return ok (a[0].f0, b[0].f0, f[0]->f0);
> +}
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 
21284 (AG Nuernberg)

Reply via email to