-
Привет! Ассемблер странный какой-то в FPC. Совсем с Delphi не совместим. Если у Delphi переменная и есть смещение, то в FPC надо rip подставить + смещение. Это верно или есть другие возможности? Нужно загрузить dqword из памяти в регистр. procedure BlendDataScLineSSSE3(sA, dA: TAddress; dLen: dword; dOpacity: byte);
const
PExtractAlpha: UInt128 = ($0100010001000100, $0100010001000100); PQuadAlpha1: UInt128 = ($FF03FF03FF03FF03, $FF07FF07FF07FF07); PExtractPixel: UInt128 = ($FF03FF02FF01FF00, $FF07FF06FF05FF04); PClearMask: UInt128 = ($FFFFFFFFFFFFFFFF, $FFFFFFFFFFFFFFFF);
asm
xor r10, r10
mov r10d, dLen movzx r11, r10b shr r10d, 2 and r11, 03h
mov r8, dA
movdqu xmm6, [rip + PExtractAlpha] movdqu xmm7, [rip + PExtractPixel]
test r10, r10 jz @@CheckCounter
movdqu xmm12, [rip + PClearMask] movdqu xmm8, xmm12 psrlw xmm8, 8 psrldq xmm12, 8
movdqu xmm11, [rip + PQuadAlpha1] movdqu xmm9, xmm6 psrlw xmm9, 8
movzx r9d, dOpacity movd xmm13, r9d
pshufb xmm13, xmm6
-
Или вот например, такой код под 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;
-
dmk, извини, но зачем тебе асм, эсли ты его знать/учить не хочешь?
-
Под Delphi работает, под FPC нет. Что не так? А учительствовать не нужно. Нет желания пояснить, то лучше мимо проходите. Не все бегать могут, но ноги же им нужны :)
-
Не то, чтобы я его совсем не знал. У меня очень много на ассемблере написано. Огромное большинство работает без проблем. Проблемы возникли только с self под FPC. Но ведь это особенности языка и передачи параметров. Правильно?
-
Но ведь это особенности языка - какого? ))
У меня очень много на ассемблере значит поставить bp и посмотреть disasm не проблема?
-
>значит поставить bp и посмотреть disasm не проблема? Проблема. В Lazarus нет такого отладочного окна как в Delphi.
-
Есть, Сtrl+Alt+D Сtrl+Alt+R ...
-
Ну вот, реальная помощь. Глаз уже замылился. Не нашел с первого раза. Спасибо!
-
RIP? Это что за чудеса такие? А если, к примеру:
lea rax, PExtractAlpha movdqu xmm7, [rax]
Так работать будет?
-
Код из [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;
-
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 //Адрес назначения
-
У FPC 3.0.0. какие то проблемы с выравниванием. В гугле ничего не нашел кроме rip. Хотя movdqu - это невыровненная ячейка, а movdqa - с выравниванием. Не знаю. В Дельфи работает, в FPC - хрень. Надо разбираться.
-
Очистранно, нука скинь свой пример на rouse@grandsmeta.ru в виде проекта, доберусь до работы попробую пошаманить, ты лазарус используешь ведь?
-
Короче проверил, все работает, но есть нюансы с эпилогом асм функций. Пролог выставляется автоматом и ты его не учитываешь, поэтому падает:
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.
-
А... про загрузку забыл, щас тоже проверю
-
Мдя, действительно, 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]
-
// не выпендриваясь делаем эпилог ручками 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
-
Ну блин, я ж тебе направление даже подсказал, чего сам не перепроверишь? :)
Ня, тот-же стек, только немного больше уплывший под 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 ;
-
на, вот еще советую нормальный отладчик. а то от лазарусного у меня чуть крыша не сдвинулась с его выхлопом: http://x64dbg.com/
-
Умные люди тут говорят :)
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;
-
Не, не хочет никак. Может проблема в том, что это не класс, а 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;
Просто удобнее с записью чем с классом.
-
Сам он свой код так интерпретирует:
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)
-
Ну тут даже не знаю как помочь, раз ты не хочешь отладчик в руки брать.
-
Да уже разобрался. У него переменная 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;
-
Работает раза в 2 быстрее чем код который генерит FPC или дельфи. Потому и нужен асм. Приятно все закрутилось. Шустрее :)
-
И спасибо умным людям :) Пришлось убрать ret.
-
Это всегда пожалуйста ;)
-
> Пришлось убрать 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
-
>будет быстрее твоего асм Тут неверно. Генерит медленный код. 2 чтения из памяти + сравнение * 4 против моих 4-х сравнений с памятью. У меня фпс в 2 раза поднимается почти с функцией на асм.
-
А за NoFrame спасибо! Еще быстре стала ;)
-
> dmk © (15.02.17 17:20) [29]
странно, у тебя x,y перед вызовом тоже читаются и call/ret ещё запись/чтение. ( длина кода, правда, в ~2 раза меньше - сравнение reg,[reg] и короткие переходы - нужно будет затестить )
-
-
Функция 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;
-
> Проц i7-6950X 3 ГГц. (20 ядер). ну-ну.
Сделай простой тест (rdtsc) на один поток. У меня Asm/Inline ~ 19/15
~2х может быть только из-за ошибок в коде или логике.
-
у меня точный тест через READ TSC. Я все функции тестирую на нем.
-
-
По поводу ну-ну. Если взглянете в фотошоп, то в последних версиях (у меня CC 2017) во многих-многих местах уже многопоточность или использование GPU. У меня по тестам, даже неоптимизированный код Delphi в 8-10 раз быстрее выполняется. В оптимизированной версии кода есть случаи свыше 100%. Предсказание работает.
-
Речь о том, что тестировать лучше в одном потоке, иначе непонятно, как воспринимать эти твои "почти 2 раза" - делить на 10? Или на 12 с учётом гипертрединга? У меня в FPC быстрее паскалевский вариант со всеми оптимизациями и инлайном. Без инлайна примерно одинаково, несмотря даже на то, что компилятор генерирует более длинный asm-код.
-
>как воспринимать эти твои "почти 2 раза" Там по ссылке результат теста. Кроме того возмущения непонятны. Нравится паскалевский вариант - ради бога. Руки никто никому не выламывает слава богу :)
-
Из этой картиночки никакой ценной информации не извлечь, кроме тех же "почти 2 раза", которые написаны и текстом. Мне кажется, всё-таки ошибка в тесте, разные исходные данные, например. Менее вероятно, что это особенность железа. Хотя я тоже ничего не навязываю, хочется возиться с ассемблером - твоё право.
-
>всё-таки ошибка в тесте Стопудово ;) И в набор хромосом у меня левый. Я вообще не с этой планеты. Извините что зашел.
|