Re: __builtin_memcpy and alignment assumptions
On Fri, Jan 8, 2016 at 7:36 PM, Steve Ellcey wrote: > On Fri, 2016-01-08 at 12:56 +0100, Richard Biener wrote: >> On Fri, Jan 8, 2016 at 12:40 PM, Eric Botcazou >> wrote: >> >> I think we only assume it if the pointer is actually dereferenced, >> >> otherwise >> >> it just breaks too much code in the wild. And while memcpy dereferences, >> >> it dereferences it through a char * cast, and thus only the minimum >> >> alignment is assumed. >> > >> > Yet the compiler was generating the expected code for Steve's testcase on >> > strict-alignment architectures until very recently (GCC 4.5 IIUC) and this >> > worked perfectly. > > Yes, I just checked and I did get the better code in GCC 4.5 and I get > the current slower code in GCC 4.6. > >> Consider >> >> int a[256]; >> int >> main() >> { >> void *p = (char *)a + 1; >> void *q = (char *)a + 5; >> __builtin_memcpy (p, q, 4); >> return 0; >> } >> >> where the ME would be entitled to "drop" the char */void * conversions >> and use &a typed temps. > > I am not sure how this works but I tweaked get_pointer_alignment_1 so > that if there was no align info or if get_ptr_info_alignment returned > false then the routine would return type based alignment information > instead of default 'void *' alignment. In that case and using your > example, GCC still accessed p & q as pointers to unaligned data. > > In fact if I used int pointers: > > int a[256]; > int main() > { > int *p = (int *)((char *)a + 1); > int *q = (int *)((char *)a + 5); > __builtin_memcpy (p, q, 4); > return 0; > } > > GCC did unaligned accesses when optimizing, but when unoptimized (and > with my change) GCC did aligned accesses, which would not work on a > strict alignment machine like MIPS This seems to match what happens > with: > > int a[256]; > int main() > { > int *p = (int *)((char *)a + 1); > int *q = (int *)((char *)a + 5); > *p = *q; > return 0; > } > > When I optimize it, GCC does unaligned accesses and when unoptimized > GCC does aligned accesses which will not work on MIPS. Of course reading the fine-print in the C standard makes these testcases undefined (you use a int * type for not properly aligned pointers, -Wcast-align should warn about this). Btw, your change to get_pointer_alignment would basically boil down to doing get_object_alignment. Richard.
Re: __builtin_memcpy and alignment assumptions
On Fri, 2016-01-08 at 12:56 +0100, Richard Biener wrote: > On Fri, Jan 8, 2016 at 12:40 PM, Eric Botcazou > wrote: > >> I think we only assume it if the pointer is actually dereferenced, > >> otherwise > >> it just breaks too much code in the wild. And while memcpy dereferences, > >> it dereferences it through a char * cast, and thus only the minimum > >> alignment is assumed. > > > > Yet the compiler was generating the expected code for Steve's testcase on > > strict-alignment architectures until very recently (GCC 4.5 IIUC) and this > > worked perfectly. Yes, I just checked and I did get the better code in GCC 4.5 and I get the current slower code in GCC 4.6. > Consider > > int a[256]; > int > main() > { > void *p = (char *)a + 1; > void *q = (char *)a + 5; > __builtin_memcpy (p, q, 4); > return 0; > } > > where the ME would be entitled to "drop" the char */void * conversions > and use &a typed temps. I am not sure how this works but I tweaked get_pointer_alignment_1 so that if there was no align info or if get_ptr_info_alignment returned false then the routine would return type based alignment information instead of default 'void *' alignment. In that case and using your example, GCC still accessed p & q as pointers to unaligned data. In fact if I used int pointers: int a[256]; int main() { int *p = (int *)((char *)a + 1); int *q = (int *)((char *)a + 5); __builtin_memcpy (p, q, 4); return 0; } GCC did unaligned accesses when optimizing, but when unoptimized (and with my change) GCC did aligned accesses, which would not work on a strict alignment machine like MIPS This seems to match what happens with: int a[256]; int main() { int *p = (int *)((char *)a + 1); int *q = (int *)((char *)a + 5); *p = *q; return 0; } When I optimize it, GCC does unaligned accesses and when unoptimized GCC does aligned accesses which will not work on MIPS. Steve Ellcey sell...@imgtec.com
Re: __builtin_memcpy and alignment assumptions
On Fri, Jan 08, 2016 at 03:28:53PM +, paul_kon...@dell.com wrote: > If it really is necessary to say that memcpy is defined to behave as if it > had a cast to char* in its implementation, it would still be useful -- and > obviously valid -- to rely on the greater alignment when there is other code > in the block that uses it. And it would be helpful to have a way in the > source program to say "I want you to rely on the type alignment". We have a way to say that, look for __builtin_assume_aligned. Jakub
Re: __builtin_memcpy and alignment assumptions
> On Jan 8, 2016, at 6:32 AM, Jakub Jelinek wrote: > > On Fri, Jan 08, 2016 at 12:24:49PM +0100, Eric Botcazou wrote: >>> See some existing PR. The GCC middle-end cannot assume that pointers >>> are aligned according to their type (while at least the C language would >>> support that notion). >> >> Only on x86. It could (and used to) do it on strict-alignment architectures. > > I think we only assume it if the pointer is actually dereferenced, otherwise > it just breaks too much code in the wild. And while memcpy dereferences, it > dereferences it through a char * cast, and thus only the minimum alignment > is assumed. Is the char* cast actually part of the definition of memcpy? The fact that memcpy doesn't make use of the known alignment is a rather unfortunate issue (I'd call it a defect); it results in clearly inferior code on strict-alignment machines when the alignment is in fact clearly known. If it really is necessary to say that memcpy is defined to behave as if it had a cast to char* in its implementation, it would still be useful -- and obviously valid -- to rely on the greater alignment when there is other code in the block that uses it. And it would be helpful to have a way in the source program to say "I want you to rely on the type alignment". paul
Re: __builtin_memcpy and alignment assumptions
On Fri, Jan 8, 2016 at 12:40 PM, Eric Botcazou wrote: >> I think we only assume it if the pointer is actually dereferenced, otherwise >> it just breaks too much code in the wild. And while memcpy dereferences, >> it dereferences it through a char * cast, and thus only the minimum >> alignment is assumed. > > Yet the compiler was generating the expected code for Steve's testcase on > strict-alignment architectures until very recently (GCC 4.5 IIUC) and this > worked perfectly. > > The irony of this very questionable change is that it was made to support some > corner cases with SSE on x86 Well, it was made to make alignment propagation possible in a sensbile way and to make all those pointer conversions useless. We backtracked on the SSE x86 case with relying on the alignment stored in memory references. But of course memcpy isn't a "memory reference" in the GCC IL sense. > but of course the compiler generates the expected > code for Steve's testcase on x86 because it is _not_ strict-alignment... Sure. Consider int a[256]; int main() { void *p = (char *)a + 1; void *q = (char *)a + 5; __builtin_memcpy (p, q, 4); return 0; } where the ME would be entitled to "drop" the char */void * conversions and use &a typed temps. Richard. > -- > Eric Botcazou
Re: __builtin_memcpy and alignment assumptions
> I think we only assume it if the pointer is actually dereferenced, otherwise > it just breaks too much code in the wild. And while memcpy dereferences, > it dereferences it through a char * cast, and thus only the minimum > alignment is assumed. Yet the compiler was generating the expected code for Steve's testcase on strict-alignment architectures until very recently (GCC 4.5 IIUC) and this worked perfectly. The irony of this very questionable change is that it was made to support some corner cases with SSE on x86 but of course the compiler generates the expected code for Steve's testcase on x86 because it is _not_ strict-alignment... -- Eric Botcazou
Re: __builtin_memcpy and alignment assumptions
On Fri, Jan 8, 2016 at 12:24 PM, Eric Botcazou wrote: >> See some existing PR. The GCC middle-end cannot assume that pointers >> are aligned according to their type (while at least the C language would >> support that notion). > > Only on x86. It could (and used to) do it on strict-alignment architectures. As the GIMPLE type system treats all pointer types equal (independet on alignment) "random" types may end up in the actual arguments of the memcpy (because what matters is the pointer value, not the type). In practice this is of course usually one of the types in an original conversion chain and thus "fine" if the source language is C. I don't see that it should be dependent on strict-alignment or not (such special-cases of interpreting source language semantics are bad for portability). In the middle-end (including RTL) alignment is on memory references and the issue with things like memcpy is that it is not treated as "memory reference" with explicitely recorded alignments. I doubt "used to do it" has applied to say void foo (int *p) { if (p & ~3) link_error (); } Richard. > -- > Eric Botcazou
Re: __builtin_memcpy and alignment assumptions
On Fri, Jan 08, 2016 at 12:24:49PM +0100, Eric Botcazou wrote: > > See some existing PR. The GCC middle-end cannot assume that pointers > > are aligned according to their type (while at least the C language would > > support that notion). > > Only on x86. It could (and used to) do it on strict-alignment architectures. I think we only assume it if the pointer is actually dereferenced, otherwise it just breaks too much code in the wild. And while memcpy dereferences, it dereferences it through a char * cast, and thus only the minimum alignment is assumed. Jakub
Re: __builtin_memcpy and alignment assumptions
> See some existing PR. The GCC middle-end cannot assume that pointers > are aligned according to their type (while at least the C language would > support that notion). Only on x86. It could (and used to) do it on strict-alignment architectures. -- Eric Botcazou
Re: __builtin_memcpy and alignment assumptions
On Thu, Jan 7, 2016 at 9:05 PM, Steve Ellcey wrote: > I have a question about __builtin_memcpy and alignment. While working on > MIPS I noticed that this program: > > void foo(int *a, int *b) > { > __builtin_memcpy (a, b, 8); > } > > Is generating the following MIPS code (allowing for any alignment): > > lwl $3,3($5) > lwl $2,7($5) > lwr $3,0($5) > lwr $2,4($5) > swl $3,3($4) > swr $3,0($4) > swl $2,7($4) > swr $2,4($4) > > But it seems like it should generate this code which assumes 32 bit alignment, > since int types need to be 32 bit aligned: > > lw $3,0($5) > lw $2,4($5) > sw $3,0($4) > sw $2,4($4) > > When I look at expand_builtin_memcpy, and I look at the trees for the > source and destination, they both show pointers pointing to something > with 32 bit aligned data, but src_align and dest_align are getting set > to 8 and not to 32, in trying to track this down I get into > get_pointer_alignment_1 with this tree: > > type type size > unit size > align 32 symtab 0 alias set -1 canonical type 0x7f13ac46f690 > precision 32 min max 0x7f13ac46e800 2147483647> > pointer_to_this > > unsigned SI size unit size > > align 32 symtab 0 alias set 2 canonical type 0x7f13ac47c738> > var def_stmt GIMPLE_NOP > > version 3 > ptr-info 0x7f13ac55a1e0> > > And when I look at ptr-info (returned by SSA_NAME_PTR_INFO), I see that its > align value is zero and that is why I get an 8 instead of a 32 for alignment. > > The problem is, who/where/when should the ptr-info information get set, > or am I off base and can I not actually assume 32 bit alignment instead > of 8 bit alignment in this code? See some existing PR. The GCC middle-end cannot assume that pointers are aligned according to their type (while at least the C language would support that notion). In theory we could lessen the middle-end restriction for function parameters or frontends could insert proper __builtin_assume_aligned calls. Richard. > Steve Ellcey > sell...@imgtec.com