Re: movmemm pattern
On Mon, 25 Oct 2010, Richard Guenther wrote: Because the int * could point to unaligned data and there is no access that would prove otherwise (memcpy accepts any alignment). As previously discussed, in ISO C storing a pointer in a particular pointer type or converting to / through that type implies it is properly aligned for that type. Actually using that information could be risky - glibc headers assume that they can use unaligned accesses on non-strict-alignment targets, for example (it's possible some of that is in macros that are only used for old GCC versions, but that would need checking) which runs into problems if GCC uses the alignment information to decide to use vector instructions which really do have strict alignment requirements. -- Joseph S. Myers jos...@codesourcery.com
Re: movmemm pattern
On Oct 25, 2010, at 9:28 PM, Dave Korn wrote: On 26/10/2010 01:53, Paul Koning wrote: On Oct 25, 2010, at 3:44 PM, Richard Guenther wrote: On Mon, Oct 25, 2010 at 11:26 AM, Paul Koning paul_kon...@dell.com wrote: Question on movmemm: Given extern int *i, *j; void foo (void) { memcpy (i, j, 10); } I would expect to see argument 4 (the shared alignment) to be sizeof(int) since both argument are pointers to int. What I get instead is 1. Why is that? Because the int * could point to unaligned data and there is no access that would prove otherwise (memcpy accepts any alignment). Ok, but if I do a load on an int*, I think that is what Richard meant by an access that would prove otherwise. I get an aligned load, not an unaligned load, so in all those other cases there *is* an assumption that an int* contains a properly aligned address. This is a bit like GCC optimising away a null-pointer check if it knows you've already dereferenced the pointer. Either you've already crashed by then, or it doesn't matter. What happens if you dereference i and j before the memcpy in foo? Do you then get int-sized shared alignment in movmemM? extern int *i, *j; void foo (void) { *i; *j; memcpy (i, j, 10); } That doesn't make any difference; I still get alignment 1. paul
Re: movmemm pattern
On 26/10/2010 17:16, Paul Koning wrote: On Oct 25, 2010, at 9:28 PM, Dave Korn wrote: On 26/10/2010 01:53, Paul Koning wrote: On Oct 25, 2010, at 3:44 PM, Richard Guenther wrote: On Mon, Oct 25, 2010 at 11:26 AM, Paul Koning paul_kon...@dell.com wrote: Question on movmemm: Given extern int *i, *j; void foo (void) { memcpy (i, j, 10); } I would expect to see argument 4 (the shared alignment) to be sizeof(int) since both argument are pointers to int. What I get instead is 1. Why is that? Because the int * could point to unaligned data and there is no access that would prove otherwise (memcpy accepts any alignment). Ok, but if I do a load on an int*, I think that is what Richard meant by an access that would prove otherwise. I get an aligned load, not an unaligned load, so in all those other cases there *is* an assumption that an int* contains a properly aligned address. This is a bit like GCC optimising away a null-pointer check if it knows you've already dereferenced the pointer. Either you've already crashed by then, or it doesn't matter. What happens if you dereference i and j before the memcpy in foo? Do you then get int-sized shared alignment in movmemM? extern int *i, *j; void foo (void) { *i; *j; memcpy (i, j, 10); } That doesn't make any difference; I still get alignment 1. That sounds like a missed optimisation opportunity to me, but maybe there's some reason the compiler can't infer a larger alignment. (Or maybe the reads got discarded, you might need volatile to avoid that?) cheers, DaveK
Re: movmemm pattern
On Oct 26, 2010, at 1:27 PM, Dave Korn wrote: On 26/10/2010 17:16, Paul Koning wrote: On Oct 25, 2010, at 9:28 PM, Dave Korn wrote: ... What happens if you dereference i and j before the memcpy in foo? Do you then get int-sized shared alignment in movmemM? extern int *i, *j; void foo (void) { *i; *j; memcpy (i, j, 10); } That doesn't make any difference; I still get alignment 1. That sounds like a missed optimisation opportunity to me, but maybe there's some reason the compiler can't infer a larger alignment. (Or maybe the reads got discarded, you might need volatile to avoid that?) No, they weren't discarded, I can see them in the output assembler code. Actually, I wrote *i = 20; *j = 10; paul
Re: movmemm pattern
On Tue, Oct 26, 2010 at 1:12 PM, Paul Koning paul_kon...@dell.com wrote: On Oct 26, 2010, at 1:27 PM, Dave Korn wrote: On 26/10/2010 17:16, Paul Koning wrote: On Oct 25, 2010, at 9:28 PM, Dave Korn wrote: ... What happens if you dereference i and j before the memcpy in foo? Do you then get int-sized shared alignment in movmemM? extern int *i, *j; void foo (void) { *i; *j; memcpy (i, j, 10); } That doesn't make any difference; I still get alignment 1. That sounds like a missed optimisation opportunity to me, but maybe there's some reason the compiler can't infer a larger alignment. (Or maybe the reads got discarded, you might need volatile to avoid that?) No, they weren't discarded, I can see them in the output assembler code. Actually, I wrote *i = 20; *j = 10; Alignment propagation (bit-CCP) doesn't (yet) exploit information from such a load (on x86 it couldn't - that architecture can handle unaligned loads just fine). Richard. paul
Re: movmemm pattern
On Mon, Oct 25, 2010 at 11:26 AM, Paul Koning paul_kon...@dell.com wrote: Question on movmemm: Given extern int *i, *j; void foo (void) { memcpy (i, j, 10); } I would expect to see argument 4 (the shared alignment) to be sizeof(int) since both argument are pointers to int. What I get instead is 1. Why is that? Because the int * could point to unaligned data and there is no access that would prove otherwise (memcpy accepts any alignment). Richard. If I have extern int i[10], j[10]; then I do get larger alignment as expected. paul
Re: movmemm pattern
On Oct 25, 2010, at 3:44 PM, Richard Guenther wrote: On Mon, Oct 25, 2010 at 11:26 AM, Paul Koning paul_kon...@dell.com wrote: Question on movmemm: Given extern int *i, *j; void foo (void) { memcpy (i, j, 10); } I would expect to see argument 4 (the shared alignment) to be sizeof(int) since both argument are pointers to int. What I get instead is 1. Why is that? Because the int * could point to unaligned data and there is no access that would prove otherwise (memcpy accepts any alignment). Ok, but if I do a load on an int*, I get an aligned load, not an unaligned load, so in all those other cases there *is* an assumption that an int* contains a properly aligned address. paul
Re: movmemm pattern
On 26/10/2010 01:53, Paul Koning wrote: On Oct 25, 2010, at 3:44 PM, Richard Guenther wrote: On Mon, Oct 25, 2010 at 11:26 AM, Paul Koning paul_kon...@dell.com wrote: Question on movmemm: Given extern int *i, *j; void foo (void) { memcpy (i, j, 10); } I would expect to see argument 4 (the shared alignment) to be sizeof(int) since both argument are pointers to int. What I get instead is 1. Why is that? Because the int * could point to unaligned data and there is no access that would prove otherwise (memcpy accepts any alignment). Ok, but if I do a load on an int*, I think that is what Richard meant by an access that would prove otherwise. I get an aligned load, not an unaligned load, so in all those other cases there *is* an assumption that an int* contains a properly aligned address. This is a bit like GCC optimising away a null-pointer check if it knows you've already dereferenced the pointer. Either you've already crashed by then, or it doesn't matter. What happens if you dereference i and j before the memcpy in foo? Do you then get int-sized shared alignment in movmemM? extern int *i, *j; void foo (void) { *i; *j; memcpy (i, j, 10); } cheers, DaveK