Код, созданный компилятором из Visual C++ Toolkit 2003 Ключ cl /G7 minimal.exe (G7 - optimized for Pentium 4 or Athlon) Код (Text): 00401000 /$ 55 PUSH EBP 00401001 |. 8BEC MOV EBP,ESP 00401003 |. 83EC 14 SUB ESP,14 00401006 |. 56 PUSH ESI 00401007 |. 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10] 0040100A |. 2B45 0C SUB EAX,DWORD PTR SS:[EBP+C] 0040100D |. D1F8 SAR EAX,1 0040100F |. 0345 0C ADD EAX,DWORD PTR SS:[EBP+C] 00401012 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 00401015 |. 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4] 00401018 |. 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] 0040101B |. 8B048A MOV EAX,DWORD PTR DS:[EDX+ECX*4] 0040101E |. 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX 00401021 |. 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4] 00401024 |. 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] 00401027 |. 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] 0040102A |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] 0040102D |. 8B0486 MOV EAX,DWORD PTR DS:[ESI+EAX*4] 00401030 |. 89048A MOV DWORD PTR DS:[EDX+ECX*4],EAX 00401033 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C] 00401036 |. 83C1 01 ADD ECX,1 00401039 |. 894D F8 MOV DWORD PTR SS:[EBP-8],ECX 0040103C |. 8B55 10 MOV EDX,DWORD PTR SS:[EBP+10] 0040103F |. 8955 EC MOV DWORD PTR SS:[EBP-14],EDX 00401042 |> B8 01000000 /MOV EAX,1 00401047 |. 85C0 |TEST EAX,EAX 00401049 |. 0F84 8D000000 |JE minimal.004010DC 0040104F |> 8B4D F8 |/MOV ECX,DWORD PTR SS:[EBP-8] 00401052 |. 3B4D EC ||CMP ECX,DWORD PTR SS:[EBP-14] 00401055 |. 7D 19 ||JGE SHORT minimal.00401070 00401057 |. 8B55 F8 ||MOV EDX,DWORD PTR SS:[EBP-8] 0040105A |. 8B45 08 ||MOV EAX,DWORD PTR SS:[EBP+8] 0040105D |. 8B4D F4 ||MOV ECX,DWORD PTR SS:[EBP-C] 00401060 |. 3B0C90 ||CMP ECX,DWORD PTR DS:[EAX+EDX*4] 00401063 |. 7E 0B ||JLE SHORT minimal.00401070 00401065 |. 8B55 F8 ||MOV EDX,DWORD PTR SS:[EBP-8] 00401068 |. 83C2 01 ||ADD EDX,1 0040106B |. 8955 F8 ||MOV DWORD PTR SS:[EBP-8],EDX 0040106E |.^EB DF |\JMP SHORT minimal.0040104F 00401070 |> 8B45 EC |/MOV EAX,DWORD PTR SS:[EBP-14] 00401073 |. 3B45 F8 ||CMP EAX,DWORD PTR SS:[EBP-8] 00401076 |. 7C 19 ||JL SHORT minimal.00401091 00401078 |. 8B4D EC ||MOV ECX,DWORD PTR SS:[EBP-14] 0040107B |. 8B55 08 ||MOV EDX,DWORD PTR SS:[EBP+8] 0040107E |. 8B048A ||MOV EAX,DWORD PTR DS:[EDX+ECX*4] 00401081 |. 3B45 F4 ||CMP EAX,DWORD PTR SS:[EBP-C] 00401084 |. 7E 0B ||JLE SHORT minimal.00401091 00401086 |. 8B4D EC ||MOV ECX,DWORD PTR SS:[EBP-14] 00401089 |. 83E9 01 ||SUB ECX,1 0040108C |. 894D EC ||MOV DWORD PTR SS:[EBP-14],ECX 0040108F |.^EB DF |\JMP SHORT minimal.00401070 00401091 |> 8B55 F8 |MOV EDX,DWORD PTR SS:[EBP-8] 00401094 |. 3B55 EC |CMP EDX,DWORD PTR SS:[EBP-14] 00401097 |. 7C 02 |JL SHORT minimal.0040109B 00401099 |. EB 41 |JMP SHORT minimal.004010DC 0040109B |> 8B45 F8 |MOV EAX,DWORD PTR SS:[EBP-8] 0040109E |. 8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8] 004010A1 |. 8B1481 |MOV EDX,DWORD PTR DS:[ECX+EAX*4] 004010A4 |. 8955 F0 |MOV DWORD PTR SS:[EBP-10],EDX 004010A7 |. 8B45 F8 |MOV EAX,DWORD PTR SS:[EBP-8] 004010AA |. 8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8] 004010AD |. 8B55 EC |MOV EDX,DWORD PTR SS:[EBP-14] 004010B0 |. 8B75 08 |MOV ESI,DWORD PTR SS:[EBP+8] 004010B3 |. 8B1496 |MOV EDX,DWORD PTR DS:[ESI+EDX*4] 004010B6 |. 891481 |MOV DWORD PTR DS:[ECX+EAX*4],EDX 004010B9 |. 8B45 EC |MOV EAX,DWORD PTR SS:[EBP-14] 004010BC |. 8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8] 004010BF |. 8B55 F0 |MOV EDX,DWORD PTR SS:[EBP-10] 004010C2 |. 891481 |MOV DWORD PTR DS:[ECX+EAX*4],EDX 004010C5 |. 8B45 EC |MOV EAX,DWORD PTR SS:[EBP-14] 004010C8 |. 83E8 01 |SUB EAX,1 004010CB |. 8945 EC |MOV DWORD PTR SS:[EBP-14],EAX 004010CE |. 8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] 004010D1 |. 83C1 01 |ADD ECX,1 004010D4 |. 894D F8 |MOV DWORD PTR SS:[EBP-8],ECX 004010D7 |.^E9 66FFFFFF \JMP minimal.00401042 004010DC |> 8B55 0C MOV EDX,DWORD PTR SS:[EBP+C] 004010DF |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 004010E2 |. 8B4D EC MOV ECX,DWORD PTR SS:[EBP-14] 004010E5 |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] 004010E8 |. 8B0C8E MOV ECX,DWORD PTR DS:[ESI+ECX*4] 004010EB |. 890C90 MOV DWORD PTR DS:[EAX+EDX*4],ECX 004010EE |. 8B55 EC MOV EDX,DWORD PTR SS:[EBP-14] 004010F1 |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 004010F4 |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C] 004010F7 |. 890C90 MOV DWORD PTR DS:[EAX+EDX*4],ECX 004010FA |. 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14] 004010FD |. 5E POP ESI 004010FE |. 8BE5 MOV ESP,EBP 00401100 |. 5D POP EBP 00401101 \. C3 RETN Несколько вопросов: 1. Для чего строки Код (Text): 00401042 |> B8 01000000 /MOV EAX,1 00401047 |. 85C0 |TEST EAX,EAX 00401049 |. 0F84 8D000000 |JE minimal.004010DC Ведь переход никогда не будет осуществлен? Лишние 11 байт и некоторое кол-во тактов 2. Строки 00401007-00401021 - расчет среднего арифметического и сохранение на стеке [EBP-4]. Значение используется как промежуточное для вычисления другого, которое происходит следом за промежуточным. Зачем делать на стеке переменную, сохранять в неё промежуточное значение и тут же его снова извлекать для последующего расчета с ней? Почему бы промежуточный результат не держать в регистре, это бы дало экономию двух пересылок? Тем более, что до конца процедуры эта величина более не задействуется. 3. Вот такая конструкция используется вместо обычного inc: Код (Text): MOV EDX,DWORD PTR SS:[EBP-8] ADD EDX,1 MOV DWORD PTR SS:[EBP-8],EDX это опять же две лишних пересылки, и такой фрагмент повторяется несколько раз. Почему? 4. Почему пустуют регистры edi ebx? В них можно было бы один раз загрузить и держать некоторые базовые адреса/значения, которые не меняются в процедуре. Вместо этого раз за разом эти адреса загружаются то в edx, то в ecx, то в eax. Непонятно. 5. Почему в eax два раза подряд загружается [EBP-8]? Ведь аккумулятор не поменялся, и значение в нем прежнее:[EBP-8]. Такие фрагменты повторяются несколько раз. Это опять же лишние байты и время. Код (Text): 0040109B |> 8B45 F8 |MOV EAX,DWORD PTR SS:[EBP-8] 0040109E |. 8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8] 004010A1 |. 8B1481 |MOV EDX,DWORD PTR DS:[ECX+EAX*4] 004010A4 |. 8955 F0 |MOV DWORD PTR SS:[EBP-10],EDX 004010A7 |. 8B45 F8 |MOV EAX,DWORD PTR SS:[EBP-8] Или оптимизация подразумевает не уменьшение кода и ускорение работы?
там он операцию такого же вида растянул на 8 инструкций. MOV EDX,DWORD PTR SS:[EBP-8] ADD EDX,1 MOV DWORD PTR SS:[EBP-8],EDX if(*b_ptr<depth){] ... } было что то вроде mov eax,[esi] mov edx,eax mov eax,depth cmp eax,edx setng al mov ebp,eax; mov eax,ebp;этм две шли друг за другом! test al,al jz он конечно между ними еще штук 20 инструкций из цикла влепил но.... короче я после этого и стал учить асм как следует.
Непохоже... я смотрел оптимизированный код много раз (VC++ 6.0) - очень неплохо. Наверное в опциях проблема... Narkomanius кстати ты еще не видел что делает borland c++5.02 Ты имеешь в виду Borland хуже или лучше?
q_q Вот исходник на Си: процедура достаточно известная, на мой взгляд (часть процесса сортировки). Код (Text): tblIndex partition(T *a, tblIndex lb, tblIndex ub) { item t, pivot; tblIndex i, j, p; /********************************** * разделение массива a[lb..ub] * **********************************/ /* Выбираем центр - pivot*/ p = lb + ((ub - lb)>>1); pivot = a[p]; a[p] = a[lb]; /* сортируем lb+1..ub относительно центра */ i = lb+1; j = ub; while (1) { while (i < j && pivot>a[i]) i++; while (j >= i && a[j]>pivot) j--; if (i >= j) break; t = a[i]; a[i] = a[j]; a[j] = t; j--; i++; } /* центр в a[j] */ a[lb] = a[j]; a[j] = pivot; return j; green Опции компилятора только G7, больше ничего cl /G7 minimal.cpp link minimal.obj minimal.res /subsystem:windows Narkomanius Я понимаю, что это все-таки не асм, а яву, но не до такой же степени. Есть ведь минимум три регистра, которые вполне могут заменить локальные переменные, почему не воспользоваться этим, исключив кучу ненужных пересылок. Или MOV EAX,1 TEST EAX,EAX JE minimal.004010DC - нельзя же настолько буквально понимать while(1). Это даже противоречит смыслу while
S_T_A_S_ С /Ox лучше, код меньше, используются ebx и edi, дурной while исчез, фиксированные адреса сидят постоянно в одном регистре (ecx), размер сократился с 101h до 61h. Практически как в асме написан. А тогда вопрос: почему не заложена по умолчанию генерация нормального кода? Всё-таки считается что один из лучших компиляторов...
/G7 только определяет модель процессора, из которой, в частности, должен исходить компилятор, если включен какой-либо режим оптимизации.
"нормальный" - понятие весьма субъективное. Компилятор с пом. опций позволяет весьма точно задать свойства генерируемого кода. И вообще-то в основном приходится компилить без оптимизации, иначе отлаживать очень трудно. Так что выбор дефолта оправдан, IMHO
cresta Потому что по умолчанию оптимизаций нет, а ключом /G7 ты только указал процессор, но не сказал ничего оптимизировать. К /Ox можно еще добавить /Oa /vd0 /Qifist(тока нужны они в более серьезных программах), если тока для п4 то и /arch:sse2
cresta 1. Для чего строки Код (Text): 00401042 |> B8 01000000 /MOV EAX,1 00401047 |. 85C0 |TEST EAX,EAX 00401049 |. 0F84 8D000000 |JE minimal.004010DC Используй другой код. Код (Text): ... do { while (a[i] < pivot) i++; while (pivot < a[j]) j--; if (i <= j) { t = a[i]; a[i] = a[j]; a[j] = t; i++; j--; } } while (i <= j); ...
Угу, значит к /G7 нужно ещё дополнительно оговаривать ключи. А возможны случаи, когда оптимизация не нужна, (ну например она может привести к каким-то ошибкам)? q_q Конечно, можно использовать немного другое построение, но ведь явная излишняя порция кода была.
cresta вообще-то да. Например, если не-volatile переменная используется несколькими потоками, а компилятор закэшировал её в регистре. Или необоснованное применение /Oa - подобных оптимизаций. Т.е. в большинстве случаев это ошибки программиста...
cresta Наоборот, я бы сказал /G7 модификатор к ключам оптимизации и влияет только riscification\ciscification т.е. для старых процов он киск инструкции рабивает на несколько риск...