Hi! This is an attempt to fix the following testcase (reduced from gsoap) similarly how you've fixed another issue with r221795 other AAPCS regressions introduced with r221348 change. This patch passed bootstrap/regtest on {x86_64,i686,armv7hl,aarch64,powerpc64{,le},s390{,x}}-linux.
Though, it still doesn't fix profiledbootstrap on armv7hl that is broken since r221348, so other issues are lurking in there, and I must say I'm not entirely sure about this, because it changes alignment even when the original access had higher alignment. I was trying something like: struct B { char *a, *b; }; typedef struct B C __attribute__((aligned (8))); struct A { C a; int b; long long c; }; char v[3]; __attribute__((noinline, noclone)) void fn1 (C x, C y) { if (x.a != &v[1] || y.a != &v[2]) __builtin_abort (); v[1]++; } __attribute__((noinline, noclone)) int fn2 (C x) { asm volatile ("" : "+g" (x.a) : : "memory"); asm volatile ("" : "+g" (x.b) : : "memory"); return x.a == &v[0]; } __attribute__((noinline, noclone)) void fn3 (const char *x) { if (x[0] != 0) __builtin_abort (); } static struct A foo (const char *x, struct A y, struct A z) { struct A r = { { 0, 0 }, 0, 0 }; if (y.b && z.b) { if (fn2 (y.a) && fn2 (z.a)) switch (x[0]) { case '|': break; default: fn3 (x); } fn1 (y.a, z.a); } return r; } __attribute__((noinline, noclone)) int bar (int x, struct A *y) { switch (x) { case 219: foo ("+", y[-2], y[0]); case 220: foo ("-", y[-2], y[0]); } } int main () { struct A a[3] = { { { &v[1], &v[0] }, 1, 1LL }, { { &v[0], &v[0] }, 0, 0LL }, { { &v[2], &v[0] }, 2, 2LL } }; bar (220, a + 2); if (v[1] != 1) __builtin_abort (); return 0; } and this patch indeed changes the register passing, eventhough it probably shouldn't (though, the testcase doesn't fail). Wouldn't it be possible to preserve the original type (before we call build_aligned_type on it) somewhere in SRA data structures, perhaps keep expr (the new MEM_REF) use the aligned type, but type field be the non-aligned one? 2015-05-02 Jakub Jelinek <ja...@redhat.com> PR target/65956 * tree-sra.c (turn_representatives_into_adjustments): For adj.type, use TYPE_MAIN_VARIANT of repr->type with TYPE_QUALS. * gcc.c-torture/execute/pr65956.c: New test. --- gcc/tree-sra.c.jj 2015-04-20 14:35:47.000000000 +0200 +++ gcc/tree-sra.c 2015-05-01 01:08:34.092636496 +0200 @@ -4427,7 +4427,11 @@ turn_representatives_into_adjustments (v gcc_assert (repr->base == parm); adj.base_index = index; adj.base = repr->base; - adj.type = repr->type; + /* Drop any special alignment on the type if it's not on the + main variant. This avoids issues with weirdo ABIs like + AAPCS. */ + adj.type = build_qualified_type (TYPE_MAIN_VARIANT (repr->type), + TYPE_QUALS (repr->type)); adj.alias_ptr_type = reference_alias_ptr_type (repr->expr); adj.offset = repr->offset; adj.by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base)) --- gcc/testsuite/gcc.c-torture/execute/pr65956.c.jj 2015-05-01 10:32:34.730150257 +0200 +++ gcc/testsuite/gcc.c-torture/execute/pr65956.c 2015-05-01 10:32:13.000000000 +0200 @@ -0,0 +1,67 @@ +/* PR target/65956 */ + +struct A { char *a; int b; long long c; }; +char v[3]; + +__attribute__((noinline, noclone)) void +fn1 (char *x, char *y) +{ + if (x != &v[1] || y != &v[2]) + __builtin_abort (); + v[1]++; +} + +__attribute__((noinline, noclone)) int +fn2 (char *x) +{ + asm volatile ("" : "+g" (x) : : "memory"); + return x == &v[0]; +} + +__attribute__((noinline, noclone)) void +fn3 (const char *x) +{ + if (x[0] != 0) + __builtin_abort (); +} + +static struct A +foo (const char *x, struct A y, struct A z) +{ + struct A r = { 0, 0, 0 }; + if (y.b && z.b) + { + if (fn2 (y.a) && fn2 (z.a)) + switch (x[0]) + { + case '|': + break; + default: + fn3 (x); + } + fn1 (y.a, z.a); + } + return r; +} + +__attribute__((noinline, noclone)) int +bar (int x, struct A *y) +{ + switch (x) + { + case 219: + foo ("+", y[-2], y[0]); + case 220: + foo ("-", y[-2], y[0]); + } +} + +int +main () +{ + struct A a[3] = { { &v[1], 1, 1LL }, { &v[0], 0, 0LL }, { &v[2], 2, 2LL } }; + bar (220, a + 2); + if (v[1] != 1) + __builtin_abort (); + return 0; +} Jakub