[llvm-dev] Where's the optimiser gone (part 9): bit twiddling not recognised
Stefan Kanthak via llvm-dev
llvm-dev at lists.llvm.org
Mon Dec 17 15:40:37 PST 2018
Hi @ll,
compile with -O3 -m32 -march=i686 (see <https://godbolt.org/z/fjjUl6>)
unsigned long lreverse(unsigned long x) // swap all bits
{
x = ((x & 0xAAAAAAAAUL) >> 1)
| ((x & ~0xAAAAAAAAUL) << 1);
x = ((x & 0xCCCCCCCCUL) >> 2)
| ((x & ~0xCCCCCCCCUL) << 2);
x = ((x & 0xF0F0F0F0UL) >> 4)
| ((x & ~0xF0F0F0F0UL) << 4);
x = ((x & 0xFF00FF00UL) >> 8)
| ((x & ~0xFF00FF00UL) << 8);
x = ((x & 0xFFFF0000UL) >> 16)
| ((x & ~0xFFFF0000UL) << 16);
return x;
}
lreverse: # @lreverse
mov eax, dword ptr [esp + 4]
mov ecx, eax
shr ecx, 1
and ecx, 1431655765
and eax, 1431655765
lea eax, [ecx + 2*eax]
mov ecx, eax
shr ecx, 2
and ecx, 858993459
and eax, 858993459
lea eax, [ecx + 4*eax]
mov ecx, eax
shr ecx, 4
and ecx, 252645135
shl eax, 4
and eax, -252645136
or eax, ecx
#ifndef _OPTIMISER_GONE_FISHING // until here, almost perfect;
bswap eax // the next 7 instructions but can
#else // be replaced by a single BSWAP
mov ecx, eax
shr ecx, 8
and ecx, 16711935
shl eax, 8
and eax, -16711936
or eax, ecx
rol eax, 16
#endif
ret
unsigned long long llreverse(unsigned long long x)
{
#if 0
x = ((x & 0xAAAAAAAAAAAAAAAAULL) >> 1)
| ((x & ~0xAAAAAAAAAAAAAAAAULL) << 1);
x = ((x & 0xCCCCCCCCCCCCCCCCULL) >> 2)
| ((x & ~0xCCCCCCCCCCCCCCCCULL) << 2);
x = ((x & 0xF0F0F0F0F0F0F0F0ULL) >> 4)
| ((x & ~0xF0F0F0F0F0F0F0F0ULL) << 4);
x = ((x & 0xFF00FF00FF00FF00ULL) >> 8)
| ((x & ~0xFF00FF00FF00FF00ULL) << 8);
x = ((x & 0xFFFF0000FFFF0000ULL) >> 16)
| ((x & ~0xFFFF0000FFFF0000ULL) << 16);
x = ((x & 0xFFFFFFFF00000000ULL) >> 32)
| ((x & ~0xFFFFFFFF00000000ULL) << 32);
return x;
#else
x = ((x >> 1) & ~0xAAAAAAAAAAAAAAAAULL)
| ((x << 1) & 0xAAAAAAAAAAAAAAAAULL);
x = ((x >> 2) & ~0xCCCCCCCCCCCCCCCCULL)
| ((x << 2) & 0xCCCCCCCCCCCCCCCCULL);
x = ((x >> 4) & ~0xF0F0F0F0F0F0F0F0ULL)
| ((x << 4) & 0xF0F0F0F0F0F0F0F0ULL);
x = ((x >> 8) & ~0xFF00FF00FF00FF00ULL)
| ((x << 8) & 0xFF00FF00FF00FF00ULL);
x = ((x >> 16) & ~0xFFFF0000FFFF0000ULL)
| ((x << 16) & 0xFFFF0000FFFF0000ULL);
return (x >> 32) | (x << 32);
#endif
}
llreverse: # @llreverse
push esi
mov eax, dword ptr [esp + 8]
mov ecx, dword ptr [esp + 12]
mov edx, eax
shr edx
mov esi, ecx
shr esi
#ifdef OPTIMISER_GONE_FISHING
and esi, 1431655765
and edx, 1431655765
and ecx, 1431655765
and eax, 1431655765
#else
push ebx
mov ebx, 1431655765
and esi, ebx
and edx, ebx
and ecx, ebx
and eax, ebx
#endif
lea edx, [edx + 2*eax]
lea eax, [esi + 2*ecx]
mov ecx, eax
shr ecx, 2
mov esi, edx
shr esi, 2
#ifdef OPTIMISER_GONE_FISHING
and esi, 858993459
and ecx, 858993459
and edx, 858993459
and eax, 858993459
#else
mov ebx, 858993459
and esi, ebx
and ecx, ebx
and edx, ebx
and eax, ebx
#endif
lea eax, [ecx + 4*eax]
lea edx, [esi + 4*edx]
mov ecx, edx
shr ecx, 4
mov esi, eax
shr esi, 4
#ifdef OPTIMISER_GONE_FISHING
and esi, 252645135
and ecx, 252645135
#else
mov ebx, 252645135
and esi, ebx
and ecx, ebx
#endif
shl edx, 4
shl eax, 4
#ifdef OPTIMISER_GONE_FISHING
and eax, -252645136
#else
not ebx
and eax, ebx
#endif
or eax, esi
#ifdef OPTIMISER_GONE_FISHING
and edx, -252645136
#else
and edx, ebx
pop ebx
#endif
or edx, ecx
#ifndef OPTIMISER_GONE_FISHING // until here, quite good;
bswap eax // the next 14 instructions but can
bswap edx // be replaced by a two BSWAPs
#else
mov ecx, eax
shr ecx, 8
mov esi, edx
shr esi, 8
and esi, 16711935
and ecx, 16711935
shl eax, 8
shl edx, 8
and edx, -16711936
or edx, esi
and eax, -16711936
or eax, ecx
rol edx, 16
rol eax, 16
#endif
pop esi
ret
More information about the llvm-dev
mailing list