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
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.
Created attachment 37817 [details] prevent var alias Jan, does this look reasonable?
Oh, and in case it isn't obvious, -free-loop-vectorize is what triggers the alignment increase of arrays in pass_ipa_increase_alignment.
I think this looks reasonable. OTOH we might simply choose to prevail the decl with bigger alignment?
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.
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
Fixed. Testcase doesn't fail on gcc-5 due to sem_variable::equals_wpa rejecting DECL_ALIGN diferences.