Я не обученный компьютерный ученый, поэтому я не знаю всех или большинства деталей, касающихся компиляции и т. Д., Но я всегда думал, что мои c-программы скомпилированы в машинный код, который я могу просмотреть с помощью флага -S с помощью gcc.
Я также подумал, что чем ближе мой код напоминает машинный код, тем быстрее компьютер сможет его выполнить. Поэтому я решил проверить это.
Я написал два тестовых файла, чтобы вычислить простую арифметическую задачу.
// test1.c
int main(int argc, char* argv[]){
int x = 4243;
int y = 3235;
int z = 613*x + 725*y;
return 0;
}
// test2.c
int main(int argc, char* argv[]){
int x = 4243;
int y = 3235;
int z = ( ( ( ( ( ( ( x << 3 ) + x ) << 1 ) + x ) << 3 ) + x ) << 2 ) + x +
( ( ( ( ( ( ( ( ( y << 2 ) + y ) << 1 ) + y ) << 2 ) + y ) << 2 ) + y ) << 2 ) + y;
return 0;
}
Я знаю, что сделал этот пример намного сложнее, чем необходимо, но когда я попробовал его на более простом примере, разница была не столь очевидна.
Теперь, если я скомпилирую с флагом gcc -S, машинный код будет содержать 31 строку для test1.s и 47 строк для test2.s
Каковы возможные объяснения? Не ошибочно ли предположение, что меньшее количество строк машинного кода означает более быстрое выполнение? Используется ли файл .s для чего-либо до создания двоичного файла? Является ли моя игрушка подделкой?
Спасибо за любые идеи
Раньше было время, когда процессоры были очень простыми и простыми, и трюки со сдвигом битов, подобные тому, который вы пытались сделать выше, могли фактически дать лучшую производительность, чем встроенные инструкции умножения CPU. (За счет длины программы: серия команд смены может и не может быть быстрее, чем одна команда умножения, но она, безусловно, будет длиннее.) Я считаю, что это верно до 80286.
Даже было время (помните Z80, кто-нибудь?), Когда процессоры были настолько просты, что у них даже не было встроенных команд умножения, поэтому нам приходилось вызывать подпрограммы для умножения чисел, и эти подпрограммы, конечно, содержали бы циклы это будет повторять столько раз, сколько раз умножается число битов, так что эти трюки со сдвигом битов давали бы намного, намного лучшую производительность в то время. (И опять же, это было бы за счет длины программы: вызов процедуры умножения занимает меньше байтов, чем выполнение двух или более операций сдвига.)
Но в настоящее время ничего подобного больше не сохраняется. Ваш (предположительно современный) процессор, безусловно, имеет встроенную инструкцию умножения, которая номинально выполняется за очень небольшое количество тактов, (маленький, как в, 3) поэтому его использование должно выполняться быстрее (и быть меньше), чем разбивать умножение на несколько операций сдвига, каждая из которых номинально выполняется за один такт.
И я говорю «номинально», потому что с предварительной выборкой, конвейерной передачей, кэшированием и т. Д. Даже представление о том, что вы можете заранее знать, сколько тактов потребуется для любой данной инструкции, больше не выполняется.
Итак, коротко говоря: «научиться перестать беспокоиться и любить бомбу».
Если вы пишете для процессора, который не имеет инструкции умножения (такие процессоры существуют), и если вам нужно вычислить 613*x + 725*y
много раз, тогда, возможно, стоило бы написать собственный код, сдвигающий биты.
Но вам, вероятно, придется написать его на ассемблере, чтобы сделать это быстрее, чем встроенная в компилятор функция умножения.