Bug 69990 - [6 Regression] decl alignment not respected
Summary: [6 Regression] decl alignment not respected
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: ipa (show other bugs)
Version: 6.0
: P2 normal
Target Milestone: 6.0
Assignee: Alan Modra
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2016-02-27 11:47 UTC by Alan Modra
Modified: 2016-03-03 03:03 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-02-28 00:00:00


Attachments
prevent var alias (322 bytes, patch)
2016-02-28 23:12 UTC, Alan Modra
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Alan Modra 2016-02-27 11:47:27 UTC
The following testcase on powerpc64le-linux results in
/usr/local/powerpc64le-linux/bin/ld: pack.o: In function `main':
pack.c:(.text.startup+0x10): error: R_PPC64_TOC16_LO_DS not a multiple of 4
/usr/local/powerpc64le-linux/bin/ld: final link failed: Bad value


/* -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 d;

int main(void)
{
  struct S0 *f[] = { c, (struct S0 *)&d };
  return __builtin_printf ("%x %x %x\n", a[0].f0, b[0].f0, f[0]->f0);
}


Breakpoint 1, offsettable_ok_by_alignment (mode=DImode, offset=0, op=0x7ffff6db39a8) at /src/gcc.git/gcc/config/rs6000/rs6000.c:7109
(gdb) p debug_rtx(op)
(symbol_ref:DI ("a") [flags 0x2] <var_decl 0x7ffff7ff5990 a>)
$1 = void
(gdb) p debug_tree(decl)
 <var_decl 0x7ffff7ff5990 a
    type <array_type 0x7ffff6da3150
        type <record_type 0x7ffff6da3c78 S0 tree_2 type_0 HI
            size <integer_cst 0x7ffff6c26480 constant 16>
            unit size <integer_cst 0x7ffff6c26498 constant 2>
            align 8 symtab 0 alias set 1 canonical type 0x7ffff6da3c78 fields <field_decl 0x7ffff6da8098 f0> context <translation_unit_decl 0x7ffff6d9f5a0 D.2852>
            pointer_to_this <pointer_type 0x7ffff6da3f18> chain <type_decl 0x7ffff6da8000 D.2840>>
        HI size <integer_cst 0x7ffff6c26480 16> unit size <integer_cst 0x7ffff6c26498 2>
        align 8 symtab 0 alias set 1 canonical type 0x7ffff6da3150
        domain <integer_type 0x7ffff6d7a1f8 type <integer_type 0x7ffff6c1d0a8 sizetype>
            DI
            size <integer_cst 0x7ffff6c262d0 constant 64>
            unit size <integer_cst 0x7ffff6c262e8 constant 8>
            align 64 symtab 0 alias set -1 canonical type 0x7ffff6d7a1f8 precision 64 min <integer_cst 0x7ffff6c26300 0> max <integer_cst 0x7ffff6c26300 0>>
        pointer_to_this <pointer_type 0x7ffff6da3498>>
    readonly used static HI file /src/tmp/ds_mem.c line 6 col 10 size <integer_cst 0x7ffff6c26480 16> unit size <integer_cst 0x7ffff6c26498 2>
    user align 128 context <translation_unit_decl 0x7ffff6d9f5a0 D.2852>
    (mem/u/c:HI (symbol_ref:DI ("a") [flags 0x2] <var_decl 0x7ffff7ff5990 a>) [1 a+0 S2 A128]) chain <var_decl 0x7ffff7ff5a20 c>>
$2 = void

So the alignment of "a" is reported as 128 bits, but in fact "a" is only 16 bit aligned as seen below in extract from assembly file.

        .comm   d,4,4
        .globl b
        .set    a,c
        .section        ".data"
        .align 4
        .set    .LANCHOR0,. + 0
        .type   b, @object
        .size   b, 2
b:
        .byte   7
        .byte   0
        .type   c, @object
        .size   c, 2
c:
        .byte   15
        .byte   0
Comment 1 Alan Modra 2016-02-28 23:10:33 UTC
symtab_node::can_increase_alignment_p rejects an increase in alignment of "c" with
  /* If target is already placed in an anchor, we can not touch its
     alignment.  */
  if (DECL_RTL_SET_P (target->decl)
      && MEM_P (DECL_RTL (target->decl))
      && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (DECL_RTL (target->decl), 0)))
    return false;

"c" has decl rtl due to "c" appearing in the constructor for "f".
gimplify_init_constructor -> tree_output_constant_def ->...-> decode_addr_const -> make_decl_rtl

No condition prevents "a" alignment from being increased.

Since aliases are created later, it seems that the alias between "a" and "c" must be prevented as in the attached patch.
Comment 2 Alan Modra 2016-02-28 23:12:35 UTC
Created attachment 37817 [details]
prevent var alias

Jan, does this look reasonable?
Comment 3 Alan Modra 2016-02-28 23:17:28 UTC
Oh, and in case it isn't obvious, -free-loop-vectorize is what triggers the alignment increase of arrays in pass_ipa_increase_alignment.
Comment 4 Richard Biener 2016-02-29 09:36:42 UTC
I think this looks reasonable.  OTOH we might simply choose to prevail the decl with bigger alignment?
Comment 5 Alan Modra 2016-02-29 14:04:23 UTC
I don't think we can make the decl with the larger alignment prevail.  Aren't we stuck with "c" due to it being referenced by the constructor?

It goes like:
1) "c" is referenced in a constructor, thus make_decl_rtl for "c"
2) make_decl_rtl puts "c" in an anchor block,
3) anchor block contents can't move, so "c" alignment can't change,
4) "a" can be changed by ipa_increase_alignment, and the alias info isn't yet available so there's no way to stop that happening,
5) "a" therefore must be prevented from aliasing "c".

I guess testing for exact equality of alignment is too strict, and I should also allow an alias from smaller to larger alignment if the larger alignment is a multiple of the smaller.
Comment 6 Alan Modra 2016-03-02 14:05:53 UTC
Author: amodra
Date: Wed Mar  2 14:05:21 2016
New Revision: 233906

URL: https://gcc.gnu.org/viewcvs?rev=233906&root=gcc&view=rev
Log:
decl alignment not respected

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.

What happens with the testcase 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.

	PR ipa/69990
gcc/
	* ipa-icf.c (sem_variable::merge): Do not merge an alias with
	larger alignment.
gcc/testsuite/
	gcc.dg/pr69990.c: New.


Added:
    trunk/gcc/testsuite/gcc.dg/pr69990.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/ipa-icf.c
    trunk/gcc/testsuite/ChangeLog
Comment 7 Alan Modra 2016-03-03 03:03:51 UTC
Fixed.  Testcase doesn't fail on gcc-5 due to sem_variable::equals_wpa rejecting DECL_ALIGN diferences.