Re: [PATCH 1/5] lib/sort: Make swap functions more generic
From: lkml
Date: Sat Mar 09 2019 - 10:54:59 EST
Thnk you for the feedback!
Andy Shevchenko wrote:
> On Thu, Feb 21, 2019 at 06:30:28AM +0000, George Spelvin wrote:
>> +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
>
> Why #ifdef is better than if (IS_ENABLED()) ?
Because CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is bool and not
tristate. IS_ENABLED tests for 'y' or 'm' but we don't need it
for something that's only on or off.
Looking through the kernel, I see both, but #ifdef or #if defined()
are definitely in the majority:
lib/lzo/lzo1x_compress.c:#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ64)
lib/siphash.c:#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
lib/string.c:#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
lib/strncpy_from_user.c:#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
lib/zlib_inflate/inffast.c:#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
I see a few IS_ENABLED uses in include/crypto/ and kernel/bpf/.
It makes no real difference; #ifdef is simpler to me.
>> + (void)base;
>
> I understand the possible weirdness of the case, but 0 pointer is also good, no?
I don't quite understand the question. A NULL pointer is aligned
as far as alignment_ok is concerned. In other words, word accesses to
*NULL will (not) work just as well as byte accesses.
None of this matters because the callers never pass in NULL pointers.
>> +#else
>> + lsbits |= (unsigned int)(size_t)base;
>
> Perhaps you meant simple (uintptr_t) here and maybe above as well.
No, I meant to truncate it to the same type as "align". We only
care about the low few bits; I could have used (unsigned char) just
as well.
My reason or choosing unsigned int rather than unsigned char was
that both x86 and ARM are a tiny bit more efficient at 32-bit
operations (x86 avoids a REX prefix; ARM gates off the high half
of the ALU to save power), but only x86 does byte operations
natively.
Still, compilers know how to promote to word operations, so
maybe using unsigned char would make it clearer to the
reader that "yes, I meant to do that!".
I've changed it to:
static bool __attribute_const__
is_aligned(const void *base, size_t size, unsigned char align)
{
unsigned char lsbits = (unsigned char)size;
#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
(void)base;
#else
lsbits |= (unsigned char)(uintptr_t)base;
#endif
return (lsbits & (align - 1)) == 0;
}
Although I'm thinking of:
static bool __attribute_const__
is_aligned(const void *base, size_t size, unsigned char align)
{
unsigned char lsbits = (unsigned char)size;
(void)base;
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
lsbits |= (unsigned char)(uintptr_t)base;
#endif
return (lsbits & (align - 1)) == 0;
}
Any preference?
>> +#endif
>> + lsbits &= align - 1;
>> + return lsbits == 0;
>
> and this can be one return operation.
It was just to avoid some annoying parentheses because C's precendence
rules and GCC's warnings are fighting me here. If others prefer
"return (lsbits & (align - 1)) == 0;" I'm happy to change.
>> static void u32_swap(void *a, void *b, int size)
>
> For such primitives that operates on top of an arrays we usually append 's' to
> the name. Currently the name is misleading.
>
> Perhaps u32s_swap().
I don't worry much about the naming of static helper functions.
If they were exported, it would be a whole lot more important!
I find "u32s" confusing; I keep reading the "s" as "signed" rather
than a plural.
How about one of:
swap_bytes / swap_ints / swap_longs
swap_1 / swap_4 / swap_8
> Shouldn't simple memcpy cover these case for both 32- and 64-bit architectures?
This isn't a memcpy, it's a memory *swap*. To do it with memcpy
requires:
memcpy(temp_buffer, a, size);
memcpy(a, b, size);
memcpy(b, temp_buffer, size);
This is 1.5x as much memory access, and you have to find a large
enough temp_buffer. (I didn't think a variable-length array on
the stack would make people happy.)
Also, although it is a predictable branch, memcpy() has to check the
alignment of its inputs each call. The reason for these helpers is
to factor that out.