Различия деления / сдвига сборки - PullRequest
2 голосов
/ 22 марта 2011

Доброе утро, день или ночь,

Просматривая код сборки отладочной сборки с отключенной опцией "Suppress JIT оптимизация (...)", я заметил следующее странное поведение (bitCount - это ulong):

          int BitQuotient = (int)(bitCount / 32);

00000110  push        dword ptr [ebp+0Ch] 
00000113  push        dword ptr [ebp+8] 
00000116  push        0 
00000118  push        20h 
0000011a  call        738EF4D5 
0000011f  mov         dword ptr [ebp-44h],eax 

в отличие от

          int BitQuotient = (int)(bitCount >> 5);

00000110  mov         eax,dword ptr [ebp+8] 
00000113  mov         edx,dword ptr [ebp+0Ch] 
00000116  shrd        eax,edx,5 
0000011a  shr         edx,5 
0000011d  mov         dword ptr [ebp-44h],eax 

Почему существует такая разница в сборке?Разве компилятор не должен обнаружить, что деление на 32 - это то же самое, что сдвиг вправо на 5, и заменить код?Кроме того, что эта инструкция call делает с первым фрагментом кода?Я подозреваю, что это связано с оператором /, применяемым к неродным ulong, но это также означает, что компилятор не встроил этот тип операторов?

Редактировать: Взгляните на int BitRemainder = (int)(bitCount % 32) в отличие от int BitRemainder = (int)(bitCount & 31):

00000120  mov         eax,dword ptr [ebp+8] 
00000123  mov         edx,dword ptr [ebp+0Ch] 
00000126  mov         ecx,20h 
0000012b  cmp         edx,ecx 
0000012d  jb          00000139 
0000012f  mov         ebx,eax 
00000131  mov         eax,edx 
00000133  xor         edx,edx 
00000135  div         eax,ecx 
00000137  mov         eax,ebx 
00000139  div         eax,ecx 
0000013b  mov         eax,edx 
0000013d  xor         edx,edx 
0000013f  mov         dword ptr [ebp-48h],eax 

и

00000120  mov         eax,dword ptr [ebp+8] 
00000123  and         eax,1Fh 
00000126  mov         dword ptr [ebp-48h],eax 

Большое спасибо.

1 Ответ

3 голосов
/ 22 марта 2011

Код в вашем первом фрагменте выполняет 64-разрядное деление.Джиттер x86 не генерирует машинный код для этой строки, его было бы слишком много.Он опирается на вспомогательную функцию с именем JIT_ULDiv.Это общая стратегия для джиттера или для компилятора C в этом отношении.Вид вспомогательных функций, которые может использовать jitter, можно найти в исходном коде SSCLI20, в файле исходного кода clr / src / vm / jithelpers.cpp.Вспомогательные функции для длинных и длинных арифметических операций находятся вверху файла.

Второй фрагмент выполняет 32-разрядное деление, требуя, чтобы в строке было сгенерировано достаточно команд машинного кода.Преобразование деления в смену - это простая оптимизация.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...