* При перепечатке материалов ссылка на www.SeoLiga.ru обязательна! RSS



Простая функция Паскаля
31 марта 2009

Начнем с небольшого примера. Это простая функция Паскаля по умножению целого на константу 2.
function MulInt2(I : Integer) : Integer;
begin
Result := I * 2;
end;
Посмотрим сгенерированный код в окне CPU view. Я компилировал с включенной оптимизацией.
function MulInt2_BASM(I : Integer) : Integer;
begin
Result := I * 2;
{
add eax,eax
ret
}
end;
Здесь мы видим, что параметр передается в функцию в регистре EAX и результат возвращается в том же регистре. Это соглашение по передаче параметров через регистры (register calling convention), которое является соглашением по умолчанию в Delphi. Актуальный код очень простой, умножение на 2 заменяется сложением операнда с самим собой, I + I = 2I. Инструкция RET возвращает управление в строку, следующую за вызовом функции.
Сделаем тот же код, как чистую asm функцию.
function MulInt2_BASM2(I : Integer) : Integer;
asm
//Result := I * 2;
add eax,eax
//ret
end;
Заметим, что возврат из функции обеспечивается встроенным ассемблером.
Теперь посмотрит на код вызова функции.
Вот Паскаль код:
procedure TForm1.Button1Click(Sender: TObject);
var
I, J : Integer;

begin
I := StrToInt(IEdit.Text);
J := MulInt2_BASM2(I);
JEdit.Text := IntToStr(J);
end;
Важная для нас строка следующая
J := MulInt2_BASM2(I);
В окне CPU мы видим
call StrToInt
call MulInt2_BASM2
mov esi,eax
После вызова StrToInt из строки выше вызова нашей функции, I находится в регистре EAX. (StrToInt также следует соглашению о передаче параметров через регистры). Функция MulInt2_BASM2 вызывается, и возвращает свой результат в регистре EAX, который в следующей строке копируется в регистр ESI.
Замечание об оптимизации: Умножение на два может быть сделано двумя различными путями. С помощью инструкции MUL или сдвигом влево на один разряд. Инструкция MUL описана в руководстве разработчика (Intel IA32 SW developers manual 2) на странице 536. Данная инструкция умножает значение в регистре EAX на другой регистр, результат помещается в регистровую пару EDX:EAX. Регистровая пара необходима, потому что в результате умножения двух 32-битных регистров получается 64-бита, подобно 9*9=81 – два однозначных числа дают результат из двух цифр.
Это совпадает с соглашение об использовании регистров, которые должны быть сохранены во время работы функции, и какие можно свободно изменять. Это описано в справочной системе Дельфи.
"Выражения asm должны сохранять регистры EDI, ESI, ESP, EBP и EBX, но могут свободно изменять регистры EAX, ECX и EDX."
Отсюда мы делаем вывод, что у нас не будет проблем с изменением регистра EDX в инструкции MUL и наша функция может быть реализована следующим образом.
function MulInt2_BASM3(I : Integer) : Integer;
asm
//Result := I * 2;
mov ecx, 2
mul ecx
end;
Также используется регистр ECX, но с этим тоже все в порядке. Так как результат меньше, чем диапазон для integer, то это также корректно возвращается в EAX. Но если I больше половины диапазона integer, то произойдет переполнение и результат будет неверным.
Реализация с помощью сдвига влево на один разряд
function MulInt2_BASM4(I : Integer) : Integer;
asm
//Result := I * 2;
shl eax,1
end;
Время выполнения в данном случае меньше. Мы можем также проконсультироваться с документацией Intel или AMD по таблицам латентности (latency) и по пропускной способности (throughput). От переводчика: в дальнейшем в документе будут использоваться термины - latency и throughput без перевода или латентность, поскольку нет хорошего эквивалента этим терминам или же будет использоваться термин пенальти. Смысл этих терминов следующий, команда может быть выполнена без пенальти (throughput). За минимальное время и с пенальти (latency) за полное, это особенность работы с конвейерами, на мой взгляд, автору стоило заострить эту особенность в данном месте, возможно, это будет сделано позже. Инструкции ADD и MOV выполняются за 0.5 цикла в обоих случаях, Инструкции MUL за 14-18 циклов (latency) и 5 циклов (throughput). Инструкции SHL за 4 цикла (latency) и 1 цикл (throughput). Версия, выбранная в Delphi наиболее эффективна для процессоров P4 и вероятно также для Athlon и P3.
Не рассматриваются: версия MUL против IMUL, контроль диапазона, другие соглашения о вызове, измерение производительности, подсчет тактов для других процессоров, подсчет тактов для CALL + RET, расположение адреса возврата и другое.


Теги: язык программирования html, программирование с нуля Borland Delphi

Статьи по теме:

Свойство CurrentY
IndexName
Создание отчетов из кода
Автоматизация административных функций
Компонент TQRDBText
Свойство Size для Bands
Интеграция OLAP и ИАД
Сабклассинг окон с помощью Windows API
Translate
Метод NewPage
Комплексный подход к обработке информации
Событие OnPreview
Пространства имен в Delphi
RepageIndexFile
Требования к системам электронного документооборота
| Borland Delphi | vitek |
 


Пн Вт Ср Чт Пт Сб Вс
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30


     



Rambler's Top100

Данный сайт или домен продается ICQ: 403-353-727

© 2009 Seoliga.ru | Borland Delphi | Простая функция Паскаля. Регион сайта: Москва и Санкт-Петербург