Re: __builtin_memcpy and alignment assumptions

2016-01-11 Thread Richard Biener
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  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

2016-01-08 Thread Steve Ellcey
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  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

2016-01-08 Thread Richard Biener
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


Re: __builtin_memcpy and alignment assumptions

2016-01-08 Thread Eric Botcazou
> 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

2016-01-08 Thread Jakub Jelinek
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

2016-01-08 Thread Richard Biener
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

2016-01-08 Thread Richard Biener
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  typed temps.

Richard.

> --
> Eric Botcazou


Re: __builtin_memcpy and alignment assumptions

2016-01-08 Thread Jakub Jelinek
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

2016-01-08 Thread Paul_Koning

> 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