• dmk © (14.02.17 20:34) [0]
    Привет!

    Ассемблер странный какой-то в 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://pda.delphimaster.net/?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]
    >всё-таки ошибка в тесте
    Стопудово ;) И в набор хромосом у меня левый. Я вообще не с этой планеты. Извините что зашел.
Есть новые Нет новых   [134427   +34][b:0.001][p:0.005]