[PATCH 1/6] make byte swapping macros less opaque to the optimizer
Matt Turner
mattst88 at gmail.com
Thu Apr 28 15:33:25 PDT 2011
On Thu, Apr 28, 2011 at 4:36 PM, Siarhei Siamashka
<siarhei.siamashka at gmail.com> wrote:
> On Thu, Apr 28, 2011 at 2:33 AM, Matt Turner <mattst88 at gmail.com> wrote:
>> diff --git a/include/misc.h b/include/misc.h
>> index 803f5ba..b7a3fd2 100644
>> --- a/include/misc.h
>> +++ b/include/misc.h
>> @@ -240,32 +240,17 @@ xstrtokenize(const char *str, const char* separators);
>> #define SwapRestL(stuff) \
>> SwapLongs((CARD32 *)(stuff + 1), LengthRestL(stuff))
>>
>> -/* byte swap a 32-bit value */
>> -#define swapl(x, n) { \
>> - n = ((char *) (x))[0];\
>> - ((char *) (x))[0] = ((char *) (x))[3];\
>> - ((char *) (x))[3] = n;\
>> - n = ((char *) (x))[1];\
>> - ((char *) (x))[1] = ((char *) (x))[2];\
>> - ((char *) (x))[2] = n; }
>> -
>> -/* byte swap a short */
>> -#define swaps(x, n) { \
>> - n = ((char *) (x))[0];\
>> - ((char *) (x))[0] = ((char *) (x))[1];\
>> - ((char *) (x))[1] = n; }
>> -
>> /* copy 32-bit value from src to dst byteswapping on the way */
>> -#define cpswapl(src, dst) { \
>> - ((char *)&(dst))[0] = ((char *) &(src))[3];\
>> - ((char *)&(dst))[1] = ((char *) &(src))[2];\
>> - ((char *)&(dst))[2] = ((char *) &(src))[1];\
>> - ((char *)&(dst))[3] = ((char *) &(src))[0]; }
>> +#define cpswapl(src, dst) (dst) = lswapl((src))
>>
>> /* copy short from src to dst byteswapping on the way */
>> -#define cpswaps(src, dst) { \
>> - ((char *) &(dst))[0] = ((char *) &(src))[1];\
>> - ((char *) &(dst))[1] = ((char *) &(src))[0]; }
>> +#define cpswaps(src, dst) (dst) = lswaps((src))
>> +
>> +/* byte swap a 32-bit value */
>> +#define swapl(x, n) (*(x)) = lswapl(*(x))
>> +
>> +/* byte swap a short */
>> +#define swaps(x, n) (*(x)) = lswaps(*(x))
>
> This is not an equal replacement for the previous code. The difference
> is that the older variant of 'swapl' could accept any pointer having
> any alignment, but still do byteswap for exactly 4 bytes at that
> memory location.
>
> Just to perform an additional sanity check, the following test code can be used:
>
> -#define swapl(x, n) (*(x)) = lswapl(*(x))
> +#define swapl(x, n) do { \
> + char dummytmp1[4 - sizeof(*(x))]; \
> + char dummytmp2[sizeof(*(x)) - 4]; \
> + (*(x)) = lswapl(*(x)); \
> + } while (0)
>
> /* byte swap a short */
> -#define swaps(x, n) (*(x)) = lswaps(*(x))
> +#define swaps(x, n) do { \
> + char dummytmp1[2 - sizeof(*(x))]; \
> + char dummytmp2[sizeof(*(x)) - 2]; \
> + (*(x)) = lswaps(*(x)); \
> + } while (0)
>
> And this extra guard check already spots at least one issue:
>
> swaprep.c:436:2: error: size of array 'dummytmp2' is too large
>
> http://cgit.freedesktop.org/xorg/xserver/tree/dix/swaprep.c?id=xorg-server-1.10.1#n423
>
> One more potential pitfall is data alignment. The older variant could
> work correctly with any alignment, but the new variant will fail if
> the pointer is somehow not naturally aligned. So I think the patch is
> very dangerous and every affected line of code needs to be carefully
> reviewed.
>
> --
> Best regards,
> Siarhei Siamashka
Good call!
I wonder if these misalignments are bugs in their own right? Maybe we
should just use __builtin_bswap32 instead.
I think Keith's suggestion to make to use an inline function sounds
good. I suppose I'll tack on a patch before this series that makes the
lswap[ls] macros inline functions.
Thanks!
Matt
More information about the xorg-devel
mailing list