Jakub Jelinek wrote:
On Tue, Mar 31, 2015 at 11:47:37AM +0100, Alan Lawrence wrote:
Richard Biener wrote:
But I find it odd that on ARM passing *((aligned_int *)p) as
vararg (only as varargs?) changes calling conventions independent
of the functions type signature.
Does it? Do you have a testcase, and compilation flags, that'll make this
show up in an RTL dump? I've tried numerous cases, including AFAICT yours,
and I always get the value being passed in the expected ("unaligned")
register?
If the integral type alignment right now matters, I'd try something like:
typedef int V __attribute__((aligned (8)));
V x;
int foo (int x, ...)
{
int z;
__builtin_va_list va;
__builtin_va_start (va, x);
switch (x)
{
case 1:
case 3:
case 6:
z = __builtin_va_arg (va, int);
break;
default:
z = __builtin_va_arg (va, V);
break;
}
__builtin_va_end (va);
return z;
}
int
bar (void)
{
V v = 3;
int w = 3;
foo (1, (int) v);
foo (2, (V) w);
v = 3;
w = (int) v;
foo (3, w);
foo (4, (V) w);
v = (V) w;
foo (5, v);
foo (6, (int) v);
foo (7, x);
return 0;
}
(of course, most likely with passing a different value each time and
verification of the result).
As the compiler treats all those casts there as useless, I'd expect
that the types of the passed argument would be pretty much random.
And, note that even on x86_64, the __builtin_va_arg with V expands into
# addr.1_3 = PHI <addr.1_27(9), _31(10)>
z_35 = MEM[(V * {ref-all})addr.1_3];
using exactly the same address for int as well as V va_arg - if you increase
the overalignment arbitrarily, it will surely be a wrong IL because nobody
really guarantees anything about the overalignment.
So, I think the tree-sra.c patch is a good idea - try to keep using the main
type variants as the types in the IL where possible except for the MEM_REF
first argument (i.e. even the lhs of the load should IMHO not be
overaligned).
As Eric Botcazou said, GCC right now isn't really prepared for under or
overaligned scalars, only when they are in structs (or for middle-end in
*MEM_REFs).
Jakub
On ARM, I get the arguments being passed in r0 & r1 for every call in bar()
above. It sounds as if this is because the casts are being removed as useless;
so the only way for overalignment info to be present, is when SRA puts it there.
The only way I can get a register to be skipped, is by providing a prototype
with alignment specified via a typedef:
typedef int aligned_int __attribute__((aligned((8))));
int foo(int a, aligned_int b) {...} //compiles ok
whereas specifying alignment directly, is rejected:
nonvar.c:2:20: error: alignment may not be specified for 'b'
int foo(int a, int b __attribute__((aligned((8)))))
^
Note this is using the GNU __attribute__((aligned)) extension. Trying to use C11
_Alignas results in a frontend error either way; IIUC the C11 spec deems that
sort of thing illegal.
(1) If we wish to keep the AAPCS principle that varargs are passed just as named
args, we should use TYPE_MAIN_VARIANT inside arm_needs_doubleword_alignment,
which will then ignore overalignment on both varargs _and named args_. However
this would be silently ABI-changing....?
(2) It seems to me that SRA is the only way for overalignment info to be present
on a value, so the patch to tree-sra.c/create_access_replacement seems to make
things more consistent?
(3) Given C11 forbids overaligned arguments/parameters, do we wish GNU
__attribute__((aligned)) to allow this (via typedefs but not attributes on the
parameters themselves) ?
--Alan