#c_sharp #ассемблер #компиляция #компилятор
Игрался с замером скорости доступа к L1,L2,L3 кэша процессора средствами C# и случайно наткнулся на странное поведение компилятора (vs2017, х86, со включенной оптимизацией). Приведу адаптированный кусок кода: fixed (uint** array = new uint*[256]) { var p = array; uint iters = 1024; for (uint i = 0; i < iters; i++) p = (uint**)*p; } На выходе, цикл компилится абсолютно корректно: 011E0884 xor edx,edx //uint i = 0 011E0886 mov eax,dword ptr [eax] //p = (uint**)*p; 011E0888 inc edx //i++ 011E0889 cmp edx,400h //i < 1024 011E088F jb 011E0886 Но если изменить тип переменной iters, начинается магия: fixed (uint** array = new uint*[256]) { var p = array; ulong iters = 1024; // <--- отличие в этой строке for (uint i = 0; i < iters; i++) p = (uint**)*p; } В этом случае цикл компилится вот в такое: 00BA0888 xor edi,edi //uint i = 0 00BA088A mov esi,dword ptr [esi] //p = (uint**)*p; 00BA088C inc edi //i++ 00BA088D xor eax,eax // Д 00BA088F test eax,eax // И 00BA0891 ja 00BA089D // Ч 00BA0893 jb 00BA088A // Ь 00BA0895 cmp edi,400h //i < 1024 00BA089B jb 00BA088A Вопросы: Почему после изменения типа переменной iters, которая оптимизатором заменяется на константу, и которой по сути вообще нет, появляются лишние бестолковые инструкции? В чем сакральный смысл помеченных четырех инструкций? Сперва обнуляем eax. Потом проверяем, а не ноль ли там случаем. И потом эти джампы, которые, насколько я понимаю, никогда не сработают... Это баг или фича?
Ответы
Ответ 1
Похоже что оптимизатор не осилил убрать смесь каста uint в ulong и последующего сравнения. Каст был из (edi) в (eax, edi), и выглядит как заполнение eax нулём (через xor). 00BA088C inc edi //i++ // каст uint i в ulong. Результат в паре eax, edi 00BA088D xor eax,eax // поразрядное сравнение двух ulong // старший разряд 00BA088F test eax,eax // вместо cmp eax, 0 00BA0891 ja 00BA089D 00BA0893 jb 00BA088A // младший разряд 00BA0895 cmp edi,400h 00BA089B jb 00BA088A Т.е. вроде как оптимизатор мог догадаться, что верхний разряд можно не сравнивать, но не догадался. Оптимизатор x86 старый, не ждите от него слишком многого :)
Комментариев нет:
Отправить комментарий