Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 27.06.2021, 13:58   #1
Kronos913
Форумчанин
 
Регистрация: 10.02.2021
Сообщений: 603
По умолчанию Несколько вопросов по asm

В целях оптимизации кода, начал изучать основы, как применять ассемблер в Delphi
И возник ряд вопросов

1. На сколько я понимаю, функции inc и dec - пусть и работают быстрее, чем i:=i+1 но все равно происходит вызов функции, создание ссылки на переменную?

Потому вопрос:
Код:
asm
  inc i
end;
Правильно ли будет работать такой код, и будет ли он оптимальнее вызова функции inc ?

1.1. Собственно, в продолжении:
Если нужно a:=a+b, будет ли лучше сделать так?
Код:
asm
  add a, b
end;
2. Умножение. Увидел пример, не совсем понял
Код:
function Umnojenie(x, z: integer): integer;
asm
  mov ebx,z
  mov eax,x
  imul ebx
end;
2.1. Не совсем понял, в какой момент происходит присвоение значение итоговому значению функции
2.2. Будет ли работать такой код, или нет? Будет ли он равнозначен a:=a*b Если нет, то как правильно?
Код:
asm
  imul a, b
end;
Kronos913 вне форума Ответить с цитированием
Старый 27.06.2021, 14:14   #2
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Цитата:
Сообщение от Kronos913 Посмотреть сообщение
Правильно ли будет работать такой код, и будет ли он оптимальнее вызова функции inc ?
Да. Нет, функция inc это компилир меджик она превращается в ассемблерный inc или add

Цитата:
Сообщение от Kronos913 Посмотреть сообщение
1.1. Собственно, в продолжении:
Если нужно a:=a+b, будет ли лучше сделать так?
Код:

asm
add a, b
end;
x86 это основан на 8086 суть которого аккумуляторная архитектура. Нельзя сложить два числа находящиеся в памяти. Нужно загрузить анные в регистр и только после уже сложить с памятью.


Цитата:
Сообщение от Kronos913 Посмотреть сообщение
2.1. Не совсем понял, в какой момент происходит присвоение значение итоговому значению функции
Вот в этой строчке.
Цитата:
Сообщение от Kronos913 Посмотреть сообщение
imul ebx
Откройте учебник по ассемблеру и посмотрите куда скалываются результат умножения.
А результат функции содержится или кладется в регистр eax для integer. А подробнее нужо за
зубрить соглашения о вызовах функций.

Цитата:
Сообщение от Kronos913 Посмотреть сообщение
2.2. Будет ли работать такой код, или нет? Будет ли он равнозначен a:=a*b Если нет, то как правильно?
Не будет. Тоже самое что с add.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума Ответить с цитированием
Старый 27.06.2021, 14:51   #3
Kronos913
Форумчанин
 
Регистрация: 10.02.2021
Сообщений: 603
По умолчанию

Тогда снова сюда вопрос:
Код:
function Umnojenie(x, z: integer): integer;
asm
  mov ebx,z
  mov eax,x
  imul ebx
end;
1. Регистр ebx - отвечает за вывод данных из функции? Или же, последний регистр, к которому было обращение - из него и вернется значение?

2. По какому принципу imul ebx понял, какие переменные ему перемножить?
Последние два введенные в регистр? Регистры от первого (eax) до ebx ? Регистр ebx и регистр перед ним?

3. Вопрос по самим регистрам: то есть в принципе, их можно свободно использовать как быстро работающие переменные? На участке кода, который не вызывает других процедур/функций
Kronos913 вне форума Ответить с цитированием
Старый 27.06.2021, 17:56   #4
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,285
По умолчанию

Про inc. Код:
Код:
  i := 1;
  i := i + 1;
  Inc(i);
  asm
    inc i
  end;
Превратился в одинаковый ассемблерный код:
Код:
Unit1.pas.30: i := 1;
0044DEE0 C745FC01000000   mov [ebp-$04],$00000001
Unit1.pas.31: i := i + 1;
0044DEE7 FF45FC           inc dword ptr [ebp-$04]
Unit1.pas.32: Inc(i);
0044DEEA FF45FC           inc dword ptr [ebp-$04]
Unit1.pas.34: inc i
0044DEED FF45FC           inc dword ptr [ebp-$04]
Цитата:
Сообщение от Kronos913 Посмотреть сообщение
Регистр ebx - отвечает за вывод данных из функции? Или же, последний регистр, к которому было обращение - из него и вернется значение?
Нет и нет. Как уже сказал Pavia - читайте соглашения о вызовах (например, https://en.wikipedia.org/wiki/X86_calling_conventions). Конкретно для Дельфи - http://docwiki.embarcadero.com/RADSt...ntrol_(Delphi). integer результат функции в eax.

Цитата:
Сообщение от Kronos913 Посмотреть сообщение
По какому принципу imul ebx понял, какие переменные ему перемножить?
Эта информация закодирована в мнемонике инструкции. Количество и размер операндов определяют, где будет располагаться результат умножения (https://c9x.me/x86/html/file_module_x86_id_138.html).

Цитата:
Сообщение от Kronos913 Посмотреть сообщение
их можно свободно использовать как быстро работающие переменные?
А вы уверены, что напишите более эффективный ассемблерный код, чем компилятор? Языки высокого уровня придумали, чтобы абстрагироваться от ассемблера. Чтобы код было легче писать, читать и портировать под разные архитектуры. Компилятор не дураки писали. Так что ассемблерный код получается чуть-чуть менее эффективный, чем самописный (а эффективный ассемблерный код еще надо суметь написать). Лезть в ассемблерный код стоит, если видно, что компилятор что-то реализовал плоховато, если флаги компиляции не помогают задействовать какие-то полезные асм-инструкции.
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )
BDA вне форума Ответить с цитированием
Старый 27.06.2021, 18:32   #5
Kronos913
Форумчанин
 
Регистрация: 10.02.2021
Сообщений: 603
По умолчанию

Вот какие мысли у меня появились после прочтений нескольких статей про ассемблер в Delphi
Хотелось бы услышать мнение профи на счет того, где я прав, а где нет

1. Как я понимаю, в случае цикла for, счетчик хранится в оперативке, а в ассемблере можно один из регистров использовать как счетчик. Что, как я понял, ускорит работу?
2. Снова, for может иметь шаг только 1, или -1, а иногда может быть нужен шаг другой величины
3. На счет циклов. На сколько я понял, любой цикл на "низком уровне" является переходом к метке в случае выполнения/не выполнения условия выхода?

На практике иногда нужен цикл с центральным условием

Начало цикла
Выполнить часть цикла
Проверить условие выхода
Выполнить остаток цикла
Перейти к началу цикла

4. На деле, есть довольно много мест в программе, которые кажутся не эффективными. От чего напрашивается вывод, что может быть, можно создать более эффективный код на ассемблере

Например, недавно в одной из тем обсуждался поворот изображения на 90 градусов. И целая куча возни с присвоением указателей для scanline. Может быть, если разобраться в ассемблере, можно ощутимо ускорить этот процесс
Kronos913 вне форума Ответить с цитированием
Старый 27.06.2021, 18:56   #6
northener
ПШП
Участник клуба
 
Регистрация: 15.07.2013
Сообщений: 1,859
По умолчанию

Цитата:
Сообщение от Kronos913 Посмотреть сообщение
есть довольно много мест в программе, которые кажутся не эффективными
Когда кажется - креститься надо!
northener вне форума Ответить с цитированием
Старый 27.06.2021, 19:24   #7
BDA
МегаМодератор
СуперМодератор
 
Аватар для BDA
 
Регистрация: 09.11.2010
Сообщений: 7,285
По умолчанию

Цитата:
Сообщение от Kronos913 Посмотреть сообщение
Как я понимаю, в случае цикла for, счетчик хранится в оперативке
Компилятор и так постарается использовать только регистры, если их хватит. Как видно, счетчик i лег на регистр eax.
Код:
  for i := 1 to 10 do
    a := i;
Код:
Unit1.pas.30: for i := 1 to 10 do
0045269C B801000000       mov eax,$00000001
Unit1.pas.31: a := i;
004526A1 8BD8             mov ebx,eax
004526A3 40               inc eax
Unit1.pas.30: for i := 1 to 10 do
004526A4 83F80B           cmp eax,$0b
004526A7 75F8             jnz -$08
Цитата:
Сообщение от Kronos913 Посмотреть сообщение
for может иметь шаг только 1, или -1, а иногда может быть нужен шаг другой величины
Можно отмасштабировать счетчик, как нужно (но преобразование займет несколько инструкций). Например:
Код:
for i := 1 to 10 do
begin
  a := 3 * i - 2; // и дальше использовать уже "a"
  // полезная работа
end;
Или переписать через while (ассемблер практически такой же как у обычного for: вместо inc используется add для счетчика):
Код:
i := 1;
while i <> 31 do
begin
  // полезная работа
  inc(i, 3);
end;
Цитата:
Сообщение от Kronos913 Посмотреть сообщение
любой цикл на "низком уровне" является переходом к метке
Да.
Цитата:
Сообщение от Kronos913 Посмотреть сообщение
На практике иногда нужен цикл с центральным условием
Так и напишите бесконечный while:
Код:
while True do
begin
  // Выполнить часть цикла
  // Проверить условие выхода
  // Выполнить остаток цикла
end;
И не нужно усложнять жизнь ассемблером.
Цитата:
Сообщение от Kronos913 Посмотреть сообщение
может быть, можно создать более эффективный код на ассемблере
Может быть, дерзайте
Пишите язык программирования - это форум программистов, а не экстрасенсов. (<= это подпись )
BDA вне форума Ответить с цитированием
Старый 27.06.2021, 19:27   #8
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Цитата:
2. По какому принципу imul ebx понял, какие переменные ему перемножить?
Последние два введенные в регистр? Регистры от первого (eax) до ebx ? Регистр ebx и регистр перед ним?
В соответствии с таблицей Ирвин К. Язык ассемблера для процессоров Intel 2005

2021-06-27_19-09-23.png


Цитата:
1. Регистр ebx - отвечает за вывод данных из функции? Или же, последний регистр, к которому было обращение - из него и вернется значение?
Нет, eax.
Вам нужно выучить соглашения о вызове функций.
http://docwiki.embarcadero.com/RADSt...ter_Convention
Это самое трудное в ассемблере. Дальше будет проще.

Цитата:
3. Вопрос по самим регистрам: то есть в принципе, их можно свободно использовать как быстро работающие переменные? На участке кода, который не вызывает других процедур/функций
Да можно. Только учтите что такие команды как idiv и imul неявно используют регистры.
Это тоже надо понять и запомнить, но это не так сложно.

Цитата:
Начало цикла
Выполнить часть цикла
Проверить условие выхода
Выполнить остаток цикла
Перейти к началу цикла
В паскале есть специальные оператор continue и ряд других
Код:
for i:=0 to 1000 do
  begin
  ...
   if (i>100) then continue;
  end;
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума Ответить с цитированием
Старый 27.06.2021, 19:32   #9
Kronos913
Форумчанин
 
Регистрация: 10.02.2021
Сообщений: 603
По умолчанию

Вот пример кода

Код:
procedure RotateBitmap180(SourceBitmap: TBitmap;
          out DestBitmap: TBitmap);
type
  PixelArray=array [0..32768] of TRGBTriple;
  pPixelArray=^PixelArray;
var
  i, j: integer;
  OriginalRow : pPixelArray;
  RotatedRow : pPixelArray;

begin
      DestBitmap.PixelFormat := pf24bit;
      DestBitmap.Height:=SourceBitmap.Height;
      DestBitmap.Width:=SourceBitmap.Width;
      For j:=0 to DestBitmap.Height-1 do begin
        RotatedRow := DestBitmap.Scanline[j];
        OriginalRow := SourceBitmap.Scanline[DestBitmap.Height-j-1];
        For i:=0 to DestBitmap.Width-1 do begin
          RotatedRow[i]:=OriginalRow[DestBitmap.Width-i-1];
        end;
      end;
end;
Приходится держать переменны-указатели, после каждой строчки присваивать этим указателям новое значение. И при чем, хорошо когда поворот на 180 градусов. При повороте на 90 градусов или приходится держать целый массив этих указателей, или же на каждый пиксель присваивать указателю новое значение

По идее, через ассемблер, можно как-то напрямую обращаться к каждому пикселю, без указателей?
Ну и счетчики циклов держать в регистрах, а не в оперативке
Kronos913 вне форума Ответить с цитированием
Старый 27.06.2021, 19:49   #10
northener
ПШП
Участник клуба
 
Регистрация: 15.07.2013
Сообщений: 1,859
По умолчанию

Вы путаете ассемблер с волшебной палочкой.
northener вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Несколько вопросов Rost93 PHP 18 19.09.2012 19:38
Несколько вопросов shrek1993 Visual C++ 3 05.08.2012 18:53
несколько вопросов по C Horus92 Общие вопросы C/C++ 2 15.11.2009 16:08
несколько вопросов fitc Общие вопросы Delphi 28 14.07.2009 21:20
Несколько Вопросов Дорст Общие вопросы Delphi 3 12.11.2007 09:18