![]() |
![]() ![]() ![]() | |
|
Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|| Форумы Здесь вы можете задать свой вопрос и наверняка получите ответ |
ЧАТ |
Место для общения :)
Орешник |
Коллекция курьезных вопросов из форумов
KOL и MCK - Компактные программы на Delphi
| ||
![]() | ||
|
Чтобы не потерять эту дискуссию, сделайте закладку
« предыдущая ветвь | форум | следующая ветвь »
Асм в FPC
dmk © (14.02.17 20:34)Привет!
Ассемблер странный какой-то в FPC. Совсем с Delphi не совместим.
Если у Delphi переменная и есть смещение, то в FPC надо rip подставить + смещение. Это верно или есть другие возможности?
Нужно загрузить dqword из памяти в регистр.procedure BlendDataScLineSSSE3(sA, dA: TAddress; dLen: dword; dOpacity: byte);
const
PExtractAlpha: UInt128 = ($0100010001000100, $0100010001000100); //Для формирования маски умножения Alpha и lpADif
PQuadAlpha1: UInt128 = ($FF03FF03FF03FF03, $FF07FF07FF07FF07); //Для формирования маски умножения Alpha и lpADif
PExtractPixel: UInt128 = ($FF03FF02FF01FF00, $FF07FF06FF05FF04); //Формирование маски исходного пиксела
PClearMask: UInt128 = ($FFFFFFFFFFFFFFFF, $FFFFFFFFFFFFFFFF); //Маска очистки
asm
xor r10, r10
mov r10d, dLen //Кол-во пикселей
movzx r11, r10b //В r11 будет хранится остаток
shr r10d, 2 //Читаем по 4 пиксела
and r11, 03h //Сохраняем первые 3 бита, чтобы найти остаток
mov r8, dA //Адрес назначения
movdqu xmm6, [rip + PExtractAlpha] //Формирование маски умножения
movdqu xmm7, [rip + PExtractPixel] //Формирование маски умножения
test r10, r10 //Проверка на ноль
jz @@CheckCounter //Quad-пикселов нет
//Формируем маски очистки из одной
movdqu xmm12, [rip + PClearMask] //Читаем общую маску очистки
movdqu xmm8, xmm12 //Для создания маски инверсии
psrlw xmm8, 8 //Создаем маску инверсии
psrldq xmm12, 8 //в xmm12 маска очистки 7..0 байтов
movdqu xmm11, [rip + PQuadAlpha1] //Маска извлечения альфы для первых двух пикселов
movdqu xmm9, xmm6//PAddOne //Для прибавления единицы
psrlw xmm9, 8 //Получаем маску прибавления единицы
movzx r9d, dOpacity //Прозрачность dOpacity
movd xmm13, r9d
pshufb xmm13, xmm6 //Транслируем маску прозрачности в слова
dmk © (14.02.17 20:50) [1]Или вот например, такой код под Delphi идет на ура, а в FPC уже не работает.
Хотя компилируется замечательно и ошибок не выдает.
function TRegion.PtInRegion(x, y: integer): boolean;
asm
cmp x, self.rEX
ja @@Out
cmp x, self.rX
jl @@Out
cmp y, self.rEY
ja @@Out
cmp y, self.rY
jl @@Out
mov al, 01h
ret
@@Out:
xor al, al
end;
NoUser © (14.02.17 21:17) [2]dmk, извини, но зачем тебе асм, эсли ты его знать/учить не хочешь?
dmk © (14.02.17 21:51) [3]Под Delphi работает, под FPC нет. Что не так?
А учительствовать не нужно. Нет желания пояснить, то лучше мимо проходите.
Не все бегать могут, но ноги же им нужны :)
dmk © (14.02.17 21:55) [4]Не то, чтобы я его совсем не знал. У меня очень много на ассемблере написано. Огромное большинство работает без проблем. Проблемы возникли только с self под FPC. Но ведь это особенности языка и передачи параметров. Правильно?
NoUser © (14.02.17 22:19) [5]Но ведь это особенности языка - какого? ))
У меня очень много на ассемблере
значит поставить bp и посмотреть disasm не проблема?
dmk © (14.02.17 23:00) [6]>значит поставить bp и посмотреть disasm не проблема?
Проблема. В Lazarus нет такого отладочного окна как в Delphi.
NoUser © (15.02.17 00:53) [7]Есть,
Сtrl+Alt+D
Сtrl+Alt+R
...
dmk © (15.02.17 07:14) [8]Ну вот, реальная помощь. Глаз уже замылился. Не нашел с первого раза.
Спасибо!
Rouse_ © (15.02.17 09:30) [9]RIP? Это что за чудеса такие?
А если, к примеру:
lea rax, PExtractAlpha
movdqu xmm7, [rax]
Так работать будет?
dmk © (15.02.17 09:33) [10]Код из [1] абсолютно правильный. Ошибок нет. Но работать в FPC он не хочет. Почему не понятно. Все версии на Delphi работают без проблем.
function TRegion.PtInRegion(x, y: integer): boolean;
{begin
if (x >= rX) and (x <= rEX) then result := (y >= rY) and (y <= rEY) else result := false;
end;}
asm
mov rcx, self
cmp x, [rcx + intEX]
ja @Ex
cmp x, [rcx + intX]
jl @Ex
cmp y, [rcx + intEY]
ja @Ex
cmp y, [rcx + intY]
jl @Ex
mov rax, true
ret
@Ex:
mov rax, false
end;
На Delphi работает, в FPC нет. Байт коды от Delphi скормить не удалось.
и такая не работает:function TRegion.PtInRegion(x, y: integer): boolean;
{begin
if (x >= rX) and (x <= rEX) then result := (y >= rY) and (y <= rEY) else result := false;
end;}
asm
mov ecx, self
mov eax, [ecx + intEX]
cmp x, eax
ja @Ex
mov eax, [ecx + intX]
cmp x, eax
jl @Ex
mov eax, [ecx + intEY]
cmp y, eax
ja @Ex
mov eax, [ecx + intY]
cmp y, eax
jl @Ex
mov rax, $01
ret
@Ex:
mov rax, $00
end;
dmk © (15.02.17 09:52) [11]Rouse_ © (15.02.17 09:30) [9]
Не работает. Один раз пропустил почему-то но выдал ерунду. Второй раз не получилось.
с MMX то же самое. rip + хочет.procedure BlendDataScLineMMX(sA, dA: TAddress; dLen: dword; dOpacity: byte);
const
ShufMask: uint64 = $0100010001000100;
asm
xor r10, r10
mov r10d, dLen
movq mm6, [rip + ShufMask] //Формирование маски умножения
mov r8, dA //Адрес назначения
dmk © (15.02.17 10:05) [12]У FPC 3.0.0. какие то проблемы с выравниванием. В гугле ничего не нашел кроме rip.
Хотя movdqu - это невыровненная ячейка, а movdqa - с выравниванием.
Не знаю. В Дельфи работает, в FPC - хрень. Надо разбираться.
Rouse_ © (15.02.17 10:10) [13]Очистранно, нука скинь свой пример на rouse@grandsmeta.ru в виде проекта, доберусь до работы попробую пошаманить, ты лазарус используешь ведь?
Rouse_ © (15.02.17 12:28) [14]Короче проверил, все работает, но есть нюансы с эпилогом асм функций. Пролог выставляется автоматом и ты его не учитываешь, поэтому падает:
unit Unit1;
{$mode objfpc}{$H+}
{$ASMMODE INTEL}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs;
type
{ TForm1 }
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
{ TRegion }
TRegion = class
public
rEX, rX, rEY, rY: Cardinal;
function PtInRegion(x, y: integer): boolean; assembler;
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TRegion }
function TRegion.PtInRegion(x, y: integer): boolean;
asm
// здесь эпилог, жрет 8 байт стека, которые нужно вернуть в EBP чтобы RET выполнился
cmp x, self.rEX
ja @@Out
cmp x, self.rX
jl @@Out
cmp y, self.rEY
ja @@Out
cmp y, self.rY
jl @@Out
mov al, 01h
// не выпендриваясь делаем эпилог ручками
pop ebp
pop ebp
ret
@@Out:
xor al, al
// не выпендриваясь делаем эпилог ручками
pop ebp
pop ebp
ret
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var
R: TRegion;
begin
R := TRegion.Create;
R.rEX := 100;
R.rEY := 100;
R.rX := 0;
R.rY := 0;
ShowMessage(BoolToStr(R.PtInRegion(50, 50), True));
end;
end.
Rouse_ © (15.02.17 12:29) [15]А... про загрузку забыл, щас тоже проверю
Rouse_ © (15.02.17 13:06) [16]Мдя, действительно, RIP нужен
lea rax, PExtractAlpha
movdqu xmm6, [rax]
movdqu xmm6, [PExtractAlpha]
movdqu xmm6, [rip + PExtractAlpha]
кодируется как:000000010002C439 | 48 8D 04 25 70 A4 18 00 | lea rax,qword ptr ds:[18A470]
000000010002C441 | F3 0F 6F 30 | movdqu xmm6,dqword ptr ds:[rax]
000000010002C445 | F3 0F 6F 34 25 70 A4 18 | movdqu xmm6,dqword ptr ds:[18A470]
000000010002C44E | F3 0F 6F 35 1A E0 15 00 | movdqu xmm6,dqword ptr ds:[10018A468]
dmk © (15.02.17 13:34) [17]// не выпендриваясь делаем эпилог ручками
pop ebp
pop ebp
Так это 32 бита. У меня — 64 :) Под 64 не пашет.
У меня вот что генерит:Region64.pas:304 asm
0000000100042940 488d6424f8 lea -0x8(%rsp),%rsp
Region64.pas:305 cmp x, self.rEX
0000000100042945 3b5108 cmp 0x8(%rcx),%edx
Region64.pas:306 ja @@Out
0000000100042948 7713 ja 0x10004295d <PTINREGION+29>
Region64.pas:307 cmp x, self.rX
000000010004294A 39ca cmp %ecx,%edx
Region64.pas:308 jl @@Out
000000010004294C 7c0f jl 0x10004295d <PTINREGION+29>
Region64.pas:309 cmp y, self.rEY
000000010004294E 443b410c cmp 0xc(%rcx),%r8d
Region64.pas:310 ja @@Out
0000000100042952 7709 ja 0x10004295d <PTINREGION+29>
Region64.pas:311 cmp y, self.rY
0000000100042954 443b4104 cmp 0x4(%rcx),%r8d
Region64.pas:312 jl @@Out
0000000100042958 7c03 jl 0x10004295d <PTINREGION+29>
Region64.pas:313 mov al, 01h
000000010004295A b001 mov $0x1,%al
Region64.pas:314 ret
000000010004295C c3 retq
Region64.pas:317 xor al, al
000000010004295D 30c0 xor %al,%al
Region64.pas:318 end;
000000010004295F 488d642408 lea 0x8(%rsp),%rsp
0000000100042964 c30000000000000000000000 retq
Rouse_ © (15.02.17 13:46) [18]Ну блин, я ж тебе направление даже подсказал, чего сам не перепроверишь? :)
Ня, тот-же стек, только немного больше уплывший под 64 - отладчик возьми в руки.function TRegion.PtInRegion(x, y: integer): boolean;
;
asm
// здесь эпилог, жрет 8 байт стека, которые нужно вернуть в EBP чтобы RET выполнился
cmp x, self.rEX
ja @@Out
cmp x, self.rX
jl @@Out
cmp y, self.rEY
ja @@Out
cmp y, self.rY
jl @@Out
mov al, 01h
// не выпендриваясь делаем эпилог ручками
pop rbp
pop rbp
pop rbp
ret
@@Out:
xor al, al
// не выпендриваясь делаем эпилог ручками
pop rbp
pop rbp
pop rbp
ret
end
Rouse_ © (15.02.17 13:53) [19]на, вот еще советую нормальный отладчик. а то от лазарусного у меня чуть крыша не сдвинулась с его выхлопом: http://x64dbg.com/
Rouse_ © (15.02.17 13:58) [20]Умные люди тут говорят :)
function TRegion.PtInRegion(x, y: integer): boolean;
asm
cmp x, self.rEX
ja @@Out
cmp x, self.rX
jl @@Out
cmp y, self.rEY
ja @@Out
cmp y, self.rY
jl @@Out
mov al, 01h
jmp @@exit
@@Out:
xor al, al
@@exit:
end;
dmk © (15.02.17 14:10) [21]Не, не хочет никак.
Может проблема в том, что это не класс, а record.type
PRegion = ^TRegion;
TRegion = record
private
rX: integer; //Позиция слева
rY: integer; //Позиция сверху
rEX: integer; //Позиция справа
rEY: integer; //Позиция снизу
rW: integer; //Ширина включая первую точку
rH: integer; //Высота включая первую точку
procedure SetWidth(W: integer);
procedure SetHeight(H: integer);
procedure SetEX(EX: integer);
procedure SetEY(EY: integer);
function GetRect: TRect;
procedure SetRect(R: TRect);
public
property X: integer read rX write rX;
property Y: integer read rY write rY;
property EX: integer read rEX write SetEX;
property EY: integer read rEY write SetEY;
property W: integer read rW write SetWidth;
property H: integer read rH write SetHeight;
procedure OffsetRegion(dx, dy: integer);
function PtInRegion(x, y: integer): boolean;
procedure ClipX(var x: integer);
procedure ClipY(var y: integer);
function InRangeX(x: integer): boolean;
function InRangeY(y: integer): boolean;
function OutRangeX(x: integer): boolean;
function OutRangeY(y: integer): boolean;
function RegionInRegion(R: TRegion): boolean;
procedure Clear;
function Empty: boolean;
procedure AddPoint(dX, dY: integer);
property Rect: TRect read GetRect write SetRect;
procedure SwapX;
procedure SwapY;
procedure NormalizeX;
procedure NormalizeY;
procedure NormalizeXY;
end;
Просто удобнее с записью чем с классом.
dmk © (15.02.17 14:13) [22]Сам он свой код так интерпретирует:
0000000100042954 488b45e8 mov -0x18(%rbp),%rax
0000000100042958 8b00 mov (%rax),%eax
000000010004295A 3b45f8 cmp -0x8(%rbp),%eax
000000010004295D 7f30 jg 0x10004298f <PTINREGION+79>
000000010004295F 488b45e8 mov -0x18(%rbp),%rax
0000000100042963 8b4008 mov 0x8(%rax),%eax
0000000100042966 3b45f8 cmp -0x8(%rbp),%eax
0000000100042969 7c24 jl 0x10004298f <PTINREGION+79>
000000010004296B 488b45e8 mov -0x18(%rbp),%rax
000000010004296F 8b4004 mov 0x4(%rax),%eax
0000000100042972 3b45f0 cmp -0x10(%rbp),%eax
0000000100042975 7f12 jg 0x100042989 <PTINREGION+73>
0000000100042977 488b45e8 mov -0x18(%rbp),%rax
000000010004297B 8b400c mov 0xc(%rax),%eax
000000010004297E 3b45f0 cmp -0x10(%rbp),%eax
0000000100042981 7c06 jl 0x100042989 <PTINREGION+73>
0000000100042983 c645e001 movb $0x1,-0x20(%rbp)
0000000100042987 eb0a jmp 0x100042993 <PTINREGION+83>
0000000100042989 c645e000 movb $0x0,-0x20(%rbp)
000000010004298D eb04 jmp 0x100042993 <PTINREGION+83>
000000010004298F c645e000 movb $0x0,-0x20(%rbp)
Rouse_ © (15.02.17 14:21) [23]Ну тут даже не знаю как помочь, раз ты не хочешь отладчик в руки брать.
dmk © (15.02.17 14:39) [24]Да уже разобрался. У него переменная self слетает после первой проверки.
Если тупо rcx указать, то все в порядке.function TRegion.PtInRegion(x, y: integer): boolean;
//if (x >= rX) and (x <= rEX) then result := (y >= rY) and (y <= rEY) else result := false;
asm
cmp x, [rcx + rEX]
jg @@Out
cmp x, [rcx + rX]
jl @@Out
cmp y, [rcx + rEY]
jg @@Out
cmp y, [rcx + rY]
jl @@Out
mov al, 01h
jmp @@Ex
@@Out:
xor al, al
@@Ex:
end;
dmk © (15.02.17 14:40) [25]Работает раза в 2 быстрее чем код который генерит FPC или дельфи. Потому и нужен асм.
Приятно все закрутилось. Шустрее :)
dmk © (15.02.17 14:41) [26]И спасибо умным людям :) Пришлось убрать ret.
Rouse_ © (15.02.17 15:03) [27]Это всегда пожалуйста ;)
NoUser © (15.02.17 15:47) [28]> Пришлось убрать ret.
конечно, ты ж.noframe
не пишешь.
> Работает раза в 2 быстрее чем код который генерит FPC или
> дельфи. Потому и нужен асм.
Потому и нужен диз-асм!, чтобы 'подсказать' компилятору что тебе нужно или увидеть правильно ли он тебя 'понял'.
Аfunction TRec.Test(x,y:Integer):Boolean; inline;
begin
Result := ( (x >= a) and (x <= b) and (y >= c) and (y <= d) );
end;
будет быстрее твоего асм и даже с .noframe
dmk © (15.02.17 17:20) [29]>будет быстрее твоего асм
Тут неверно.
Генерит медленный код. 2 чтения из памяти + сравнение * 4
против моих 4-х сравнений с памятью. У меня фпс в 2 раза поднимается почти с функцией на асм.
dmk © (15.02.17 17:22) [30]А за NoFrame спасибо! Еще быстре стала ;)
NoUser © (15.02.17 22:39) [31]> dmk © (15.02.17 17:20) [29]
странно, у тебя x,y перед вызовом тоже читаются и call/ret ещё запись/чтение.
( длина кода, правда, в ~2 раза меньше - сравнение reg,[reg] и короткие переходы - нужно будет затестить )
dmk © (16.02.17 02:04) [32]>нужно будет затестить
Уже: http://hostingkartinok.com/show-image.php?id=0fa7af40519ce173cc460d598dcbedad
Проц i7-6950X 3 ГГц. (20 ядер).
Функция A - на ассемблере.
Функция Б - на Delphi.
Почти в 2 раза ;)
dmk © (16.02.17 02:10) [33]Функция A
function TRegion.PtInRegion(x, y: integer): boolean;
asm
cmp x, [rcx + rEX]
jg @@Out
cmp x, [rcx + rX]
jl @@Out
cmp y, [rcx + rEY]
jg @@Out
cmp y, [rcx + rY]
jl @@Out
mov al, 01h
jmp @@Ex
@@Out:
xor al, al
@@Ex:
end;
Функция Бfunction TRegion.PtInRegion2(x, y: integer): boolean;
begin
Result := (x >= rX) and (x <= rEX) and (y >= rY) and (y <= rEY);
end;
NoUser © (16.02.17 16:19) [34]> Проц i7-6950X 3 ГГц. (20 ядер).
ну-ну.
Сделай простой тест (rdtsc) на один поток.
У меня Asm/Inline ~ 19/15
~2х может быть только из-за ошибок в коде или логике.
dmk © (16.02.17 21:54) [35]у меня точный тест через READ TSC.
Я все функции тестирую на нем.
dmk © (16.02.17 23:21) [36]>ну-ну.
Дык многопоточная отрисовка у меня :) PaintStream фактически.
Тут же выкладывал: http://www.delphimaster.ru/cgi-bin/forum.pl?id=1486644466&n=5
dmk © (17.02.17 14:21) [37]По поводу ну-ну. Если взглянете в фотошоп, то в последних версиях (у меня CC 2017) во многих-многих местах уже многопоточность или использование GPU. У меня по тестам, даже неоптимизированный код Delphi в 8-10 раз быстрее выполняется. В оптимизированной версии кода есть случаи свыше 100%. Предсказание работает.
invis © (17.02.17 16:45) [38]Речь о том, что тестировать лучше в одном потоке, иначе непонятно, как воспринимать эти твои "почти 2 раза" - делить на 10? Или на 12 с учётом гипертрединга?
У меня в FPC быстрее паскалевский вариант со всеми оптимизациями и инлайном. Без инлайна примерно одинаково, несмотря даже на то, что компилятор генерирует более длинный asm-код.
dmk © (17.02.17 16:52) [39]>как воспринимать эти твои "почти 2 раза"
Там по ссылке результат теста. Кроме того возмущения непонятны. Нравится паскалевский вариант - ради бога. Руки никто никому не выламывает слава богу :)
invis © (17.02.17 18:29) [40]Из этой картиночки никакой ценной информации не извлечь, кроме тех же "почти 2 раза", которые написаны и текстом.
Мне кажется, всё-таки ошибка в тесте, разные исходные данные, например. Менее вероятно, что это особенность железа.
Хотя я тоже ничего не навязываю, хочется возиться с ассемблером - твоё право.
dmk © (17.02.17 18:57) [41]>всё-таки ошибка в тесте
Стопудово ;) И в набор хромосом у меня левый. Я вообще не с этой планеты. Извините что зашел.
Разрешается использование тегов форматирования текста:
версия для печати
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)
|
![]() ![]() ![]() |