Конференция "Основная" » Инструкция ANDN (asm64)
 
  • dmk © (20.02.17 09:30) [0]
    Я так понял, что ANDN (Logical AND NOT) инструкция не поддерживается Delphi? У меня XE6. Компилятор говорит Undeclared identifier.
  • Rouse_ © (20.02.17 10:01) [1]
    нет конечно, ибо BMI1. (как и TZCNT)
    Она практически никакими декомпилерами не поддерживается.
    А AND + NOT использовать не судьба?
  • dmk © (20.02.17 10:03) [2]
    blsr, blsi, blsmsk тоже не поддерживает :( короче инструкции bmi1 и dmi2 в Delphi отсутствуют.
  • dmk © (20.02.17 10:06) [3]
    >А AND + NOT использовать не судьба?
    Мне байт надо превратить в 64 бита. Не знаю как лучше сделать.
    короче есть байт 10101111b, а нужно из него сделать FF00FF00FFFFFFFFh
    У меня сейчас таблица зарнее расчитана 8 -> 64, но очень медленно получается из памяти читать.
  • dmk © (20.02.17 10:16) [4]
    Сейчас через таблицу[0..255] работает:

    mov rdx, TableAddr
    movzx eax, byte ptr [rsi]
    shl ax, 3 //Смещение в таблице
    mov rax, [rdx+rax] //Читаем строку байтов
    mov [rdi], rax //Пишем готовую строку


    Думал быстрее сделать.
  • Rouse_ © (20.02.17 10:21) [5]

    > dmk ©   (20.02.17 10:16) [4]

    Чет я слегка прифигел, нукась дай ка мне саму таблицу.
  • dmk © (20.02.17 10:27) [6]
    По описанию вроде bextr подходит, но она тоже bmi1 :(
  • dmk © (20.02.17 10:29) [7]
    Таблица расчитывается. Так не выложишь ;)
    //Процедура создает массив отображающий биты в Grayscale представлении
    //Пример: (10001111) = ($00 $FF $FF $FF $00 $00 $00 $00)
    //Используется для прорисовки при битности 1 Bpp
    //Массив занимает 1Кб
    procedure InitGrayBits;
    var
     i: byte; //Счетчик байтов
     bc: byte; //Счетчик битов

    begin
     for i := 0 to 255 do
     for bc := 0 to 7 do
       if GetBit(i, bc) then
         //Если бит установлен, то это черный цвет
         //Если не установлен, то прозрачная область, т.е. белый
         GrayBitsArray[i].Cell[7 - bc] := $00 else
         GrayBitsArray[i].Cell[7 - bc] := $FF;

     //Адрес начала массива
     GrayBitsAddr := TAddress(@GrayBitsArray[0].Cell[0]);
    end;
  • dmk © (20.02.17 10:31) [8]
    Вернее таблица занимает 2Кб
  • Rouse_ © (20.02.17 11:02) [9]
    Вот чесно говоря ничего не понятно :)
    Покажи процедуру с асмом полностью, ибо вот после этого:

    movzx eax, byte ptr [rsi]
    ...
    mov rax, [rdx+rax] //Читаем строку байтов

    без xor rax, rax имеешь шанс вылететь в трубу

    еще не понятно откуда RSI приходит
  • Rouse_ © (20.02.17 11:04) [10]
    хотя нет, про RAX это лишнее
  • dmk © (20.02.17 11:25) [11]
    Преобразует биты в байты:
    GrayBitsAddr - это таблица

    procedure BitsToBytes(Src, Dest, NumBits: uint64);
    asm
     .NOFRAME
     movq xmm0, rsi
     movq xmm1, rdi
     movq xmm2, rbx

     mov rdi, Dest //Адрес конечного буфера

     mov bl, Self.FIndexedMask
     mov rsi, Src //Адрес изображения
     mov rcx, NumBits //Кол-во бит для преобразования
     shr rcx, 3 //Делим на 8, т.к. читаем байты
     mov rdx, GrayBitsAddr //Массив Gray-представления битов
     mov r9, $FFFFFFFFFFFFFFFF
     xor rax, rax //Очистка

     cmp bl, 0
     je @@ClearMask

    @@NextByte:
     movzx eax, byte ptr [rsi] //Читаем байт изображения, или 8 Bitmap пикселей
     test al, al
     jz @@WriteWhite

     shl ax, 3 //Смещение в массиве GrayBits к нужной ячейке
     mov rax, [rdx+rax] //Читаем строку байтов из GrayBits в rax
     mov [rdi], rax //Пишем строку в конечный адрес
     jmp @@NextAddr

    @@WriteWhite:
     mov [rdi], r9  //Пишем нулевую строку в конечный адрес

    @@NextAddr:
     inc rsi //Смещение к следующему исходному байту изображения
     add rdi, 8 //Смещение в конечном адресе на 8 байт
     dec rcx
     jnz @@NextByte

     jmp @@Out

    @@ClearMask: //Каналы отключены, пишем нулевые пикселы
     mov [rdi], r9 //Пишем строку в конечный адрес
     add rdi, 8
     dec rcx
     jnz @@ClearMask

    @@Out:
     movq rbx, xmm2
     movq rdi, xmm1
     movq rsi, xmm0
    end;
  • Rouse_ © (20.02.17 11:37) [12]
    Ну в принципе норм. только вот так бы вот начало переписал:

    procedure BitsToBytes(Src, Dest, NumBits: uint64);
    asm
     .NOFRAME
     movq xmm0, rsi
     movq xmm1, rdi
     movq xmm2, rbx

     mov rdi, Dest //Адрес конечного буфера
     xor rax, rax //Очистка  

     mov bl, Self.FIndexedMask
     mov r9, $FFFFFFFFFFFFFFFF
     mov rcx, NumBits //Кол-во бит для преобразования
     shr rcx, 3 //Делим на 8, т.к. читаем байты  
     cmp bl, 0
     je @@ClearMask
     
     mov rsi, Src //Адрес изображения  
     mov rdx, GrayBitsAddr //Массив Gray-представления битов
  • Rouse_ © (20.02.17 11:40) [13]
    а, блин, за вот такое руки бы оторвать:
     movq xmm0, rsi
     movq xmm1, rdi
     movq xmm2, rbx

    у тебя чего стека нема?
    А если у меня там Extended лежит промежуточный?
  • dmk © (20.02.17 11:49) [14]
    Не, там ничего не лежит. Со стеком медленнее работает. Память все таки.

    Есть такой вариант, но он медленнее в 2 раза.
    procedure TImageStream.BitsToBytesShuf(Src, Dest, NumBits: uint64);
    const
     ShufMask: uint64 = $00000000000000FF;

    asm
     .NOFRAME
     movq xmm0, rsi
     movq xmm1, rdi
     movq xmm2, rbx

     mov rdi, Dest //Адрес конечного буфера

     mov r10b, Self.FIndexedMask
     mov rsi, Src //Адрес изображения
     mov rcx, NumBits //Кол-во бит для преобразования
     shr rcx, 3 //Делим на 8, т.к. читаем байты
     mov rdx, 8
     movq xmm4, ShufMask
     movq xmm5, xmm4

    @@NextByte:
     movzx rax, byte ptr [rsi] //Читаем байт изображения, или 8 Bitmap пикселей
     and al, r10b

     bt ax, 0
     setc bl
     shl rbx, 8

     bt ax, 1
     setc bl
     shl rbx, 8

     bt ax, 2
     setc bl
     shl rbx, 8

     bt ax, 3
     setc bl
     shl rbx, 8

     bt ax, 4
     setc bl
     shl rbx, 8

     bt ax, 5
     setc bl
     shl rbx, 8

     bt ax, 6
     setc bl
     shl rbx, 8

     bt ax, 7
     setc bl

     movq xmm3, rbx
     movq xmm4, xmm5
     pshufb xmm4, xmm3
     movq [rdi], xmm4 //Пишем строку в конечный адрес

     inc rsi //Смещение к следующему исходному байту изображения
     add rdi, rdx //Смещение в конечном адресе на 8 байт
     dec rcx
     jnz @@NextByte

    @@Out:
     movq rbx, xmm2
     movq rdi, xmm1
     movq rsi, xmm0
    end;
  • dmk © (20.02.17 11:52) [15]
    >А если у меня там Extended лежит промежуточный?

    In line with the x64 Application Binary Interface (ABI), the contents of the following registers must be preserved and restored within inline assembly functions: R12, R13, R14, R15, RDI, RSI, RBX, RBP, RSP, XMM4, XMM5, XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15.

    Уже проверял. xmm0-xmm3 всегда свободны. Потому и использую как стек. Быстрее все рабоатет.
  • dmk © (20.02.17 12:02) [16]
    имбаркадеро вообще память копирует через FPU. Ничего - работает :)
  • Rouse_ © (20.02.17 12:08) [17]
    Да, это я уже заработался, у меня половина защиты через XMM и DR регистры выстроена.
    Ошибся.
  • dmk © (20.02.17 13:26) [18]
    Интересно, а как собрать самому последовательность?

    Кое что прочитал, но пока не понял как инструкцию собрать ;(

     //Наследственные префиксы 66H, 67H, F2H and F3H.
     //Используются для новых инструкций
     //Размещаются перед REX префиксом

     //1 bit w       Определяет данные как байт или полноразмерные, где полноразмерные это 16 или 32 бита (Таблица B-6)
     //1 bit s       Определяет знак поля данных (see Table B-7)
     //2 bit sreg2   Segment register specifier for CS, SS, DS, ES (see Table B-8)
     //3 bit sreg3   Segment register specifier for CS, SS, DS, ES, FS, GS (see Table B-8)
     //3 bit eee     Specifies a special-purpose (control or debug) register (Таблица B-9)
     //4 bit tttn    Для условных инструкций определяет состояние ASSERTED (Утвержденный) или NEGATED (Отрицается) (Таблица B-12)
     //1 bit d       Определяет направление операции (Таблица B-11)

     //REX префикс (Mod Reg* R/M) - 1 байт
     //7-6  Mod
     //5-3  Reg
     //2-0  R/M

     //SIB 1 байт
     //7-6  Scale
     //5-3  Index
     //2-0  Base

     //Поле reg  (3 бита) Определитель основных регистров (Таблица B-4 или B-5) для инструкций не содержащих поле W
     //000  AX | EAX | RAX
     //001  CX | ECX | RCX
     //010  DX | EDX | RDX
     //011  BX | EBX | RBX
     //100  SP | ESP | RSP
     //101  BP | EBP | RBP
     //110  SI | ESI | RSI
     //111  DI | EDI | RDI

    REX W RXB           W   MOD REG R/M
    0100 1 100   1000 1001    11 000 010
    REX W RXB                       RAX RDX
    0100 1 000   1000 1001    11 010 011
                                          RDX RBX
  • Rouse_ © (20.02.17 13:50) [19]
    ну как в обычном ассемблирующем движке, у тебя даже REX префикс обозначен
  • dmk © (20.02.17 14:07) [20]
    VEX.NDS1.LZ.0F38.W0 F7 /r
    NOTES:
    1. ModRM:r/m is used to encode the first source operand (second operand) and VEX.vvvv encodes the second source operand (third operand).

    RMV V/V BMI1 Contiguous bitwise extract from r/m32 using r32b as control;
    store BEXTR r32a, r/m32, r32b result in r32a.

    Не очень ясно что такое NDS1 и LZ.
    W0 и W1 определяет битность 32 или 64.

    Получается $66, $0F, $38, $F7 и дальше куда регистры впихнуть непонятно ;) ПОСЛЕ или В имеющийся байт-код.
  • Rouse_ © (22.02.17 17:39) [21]
    Если я правильно помню опкоды, (дельфи под руками нет) то влетишь на ILLEGAL_INSTRUCTION
  • Rouse_ © (22.02.17 17:53) [22]
    да, забыл, возьми какойнить дизасм движок (я пользуюсь дистормом под 64 бита https://github.com/gdabah/distorm) и поэксперементируй, в конец DB нопов накидай
  • Rouse_ © (22.02.17 17:55) [23]
    ЗЫ не забудь, что у тебя 64 бита - значит REX префикс правильно выставь
  • invis © (22.02.17 19:58) [24]
    Есть ещё PANDN, которая для SIMD, её Дельфи понимает.
  • Sha © (27.02.17 01:32) [25]
    procedure TForm1.Button1Click(Sender: TObject);
    var
     a: cardinal;
     b: Int64Rec;
    begin;
     a:=$af;
     b.Lo:=a and $0f * $00204081 and $01010101 * 255;
     b.Hi:=a shr   4 * $00204081 and $01010101 * 255;
     ShowMessage(IntToHex(Int64(b),16));
     end;
  • Sha © (27.02.17 10:19) [26]
    Можно и в одну строчку, только очень длинную )

    procedure TForm1.Button1Click(Sender: TObject);
    var
     a: int64;
    begin;
     a:=$af;
     a:=(a * $0101010101010101 and $8040201008040201 xor $8141211109050301 - $8040201008040201) shr 7 and $0101010101010101 * 255;
     ShowMessage(IntToHex(a,16));
     end;
  • Sha © (27.02.17 10:28) [27]
    если нужен NOT, то надо заменить

    xor $8141211109050301

    на

    or $0101010101010100
  • Sha © (27.02.17 13:53) [28]
    более короткий вариант:

    procedure TForm1.Button1Click(Sender: TObject);
    var
     a: int64;
    begin;
     a:=$af;
     a:=(a shr 1 * $0204081020408100 or a) and $0101010101010101 * 255;
     ShowMessage(IntToHex(a,16));
     end;
  • NoUser © (27.02.17 16:07) [29]
    dmk,
    var QwTab : array [0..255] of Int64;

    procedure InitTab();
    var
    pQ:PInt64;
    A :Byte;
    begin
    A := 0;
    pQ := @QwTab;
    repeat
     pQ^ := (A shr 1 * $0204081020408100 or A) and $0101010101010101 * 255;
     Inc(pQ);
     Inc(A);
    until (A = 0);
    end;

    procedure Bt2Qws(pB:PByte; pQ:PInt64; bN:NativeInt); inline;
    var
    pT:PInt64Array;
    begin
    pT := @QwTab;
    while (bN > 0) do begin
     pQ^ := pT^[pB^];
     Inc(pQ);
     Inc(pB);
     Dec(bN);
    end;
    end;

    function Test(a:Byte):Int64;
    var
    b : array[0..7] of Byte;
    q : array[0..7] of Int64;
    begin
    InitTab();

    DebugBreak();                 // Relese -> F9 -> F7
    Bt2Qws(@b, @q, SizeOf(b));    // -> very nice asm !

    Result := QwTab[a];
    end;
  • NoUser © (27.02.17 16:22) [30]

    > У меня сейчас таблица зарнее расчитана 8 -> 64,
    > но очень медленно получается из памяти читать.

    ну, читай из облака или алгоритм меняй ))

    проблема может быть в том, что твои 20 ядер (на самом деле 10 плюс HT, который тут не нужен) 'уродуют' кэш или у тебя с выравниванием проблемы.
  • dmk © (27.02.17 16:49) [31]
    >алгоритм меняй
    Дык не работает BIM1,2 в дельфи.
  • NoUser © (27.02.17 17:44) [32]
    я от том, что замена одного чтения (из 2 чтений и 1 записи) на одну лог операцию ( чтение bim запись) тебя сильно не спасёт.

    тестер уже есть - замени bim, например, на xor - посмотри прирост в сравнении с таблицой (для одного потока, для многих )
  • Sha © (27.02.17 21:11) [33]
    Немного ускорил преобразование:

    procedure TForm1.Button1Click(Sender: TObject);
    var
     a: int64;
    begin;
     a:=$af;
     a:=(a and 254 * $0002040810204080 or a) and $0101010101010101 * 255;
     ShowMessage(IntToHex(a,16));
     end;


    Читать лучше блоками по 8 байт, в этом случае код несколько изменится:
    var
     a: array[0..99] of int64;
     b: array[0..Length(a)*8-1] of int64;

    procedure TForm1.Button6Click(Sender: TObject);
    var
     i: integer;
     x: int64;
     p: pInt64;
    begin;
     p:=@b[0];
     for i:=0 to Length(a)-1 do begin;
       x:=a[i];    p^:=(x and 254 * $0002040810204080 and $0101010101010101 or x and 1) * 255; inc(p);
       x:=x shr 8; p^:=(x and 254 * $0002040810204080 and $0101010101010101 or x and 1) * 255; inc(p);
       x:=x shr 8; p^:=(x and 254 * $0002040810204080 and $0101010101010101 or x and 1) * 255; inc(p);
       x:=x shr 8; p^:=(x and 254 * $0002040810204080 and $0101010101010101 or x and 1) * 255; inc(p);
       x:=x shr 8; p^:=(x and 254 * $0002040810204080 and $0101010101010101 or x and 1) * 255; inc(p);
       x:=x shr 8; p^:=(x and 254 * $0002040810204080 and $0101010101010101 or x and 1) * 255; inc(p);
       x:=x shr 8; p^:=(x and 254 * $0002040810204080 and $0101010101010101 or x and 1) * 255; inc(p);
       x:=x shr 8; p^:=(x and 254 * $0002040810204080 and $0101010101010101 or x and 1) * 255; inc(p);
       end;
     end;


    Можно попробовать повертеть биты, вдруг это окажется быстрее:
    procedure TForm1.Button7Click(Sender: TObject);
    var
     i: integer;
     t, x: int64;
     p: pInt64;
    begin;
     p:=@b[0];
     for i:=0 to Length(a)-1 do begin;
       x:=a[i];

       //bit twiddling: flip chessboard diagonal
       t:=(x shl 28 xor x) and $0f0f0f0f00000000; x:=(x xor t) xor t shr 28;
       t:=(x shl 14 xor x) and $3333000033330000; x:=(x xor t) xor t shr 14;
       t:=(x shl 07 xor x) and $5500550055005500; x:=(x xor t) xor t shr 07;

       p^:=x       and $0101010101010101 * 255; inc(p);
       p^:=x shr 1 and $0101010101010101 * 255; inc(p);
       p^:=x shr 2 and $0101010101010101 * 255; inc(p);
       p^:=x shr 3 and $0101010101010101 * 255; inc(p);
       p^:=x shr 4 and $0101010101010101 * 255; inc(p);
       p^:=x shr 5 and $0101010101010101 * 255; inc(p);
       p^:=x shr 6 and $0101010101010101 * 255; inc(p);
       p^:=x shr 7 and $0101010101010101 * 255; inc(p);
       end;
     end;
  • dmk © (27.02.17 21:55) [34]
    >NoUser ©   (27.02.17 16:07) [29]
    Вообще на Delphi моя процедура выглядит так:

    procedure TImageStream.BitsToBytesA(Src, Dest, NumBits: uint64);
    var
     b: byte;
     NumPixels: uint64;

    const
     crWhite: uint64 = $FFFFFFFFFFFFFFFF;

    type
     PQWord = ^uint64;

    begin
    NumPixels := (NumBits shr 3);
    repeat
      b := PByte(src)^ and FIndexedMask;
      if b = 0 then
        PQWord(Dest)^ := crWhite else
        PQWord(Dest)^ := PQWord(GrayBitsAddr + (b shl 3))^;
      Inc(Src);
      Inc(Dest, 8);
      Dec(NumPixels);
    until (NumPixels = 0);
    end;


    Инициализация таблицы не критична.
    Там микросекунды и это при загрузке происходит.
    А ваша вообще не работает :)
  • dmk © (27.02.17 21:59) [35]
    Но версия на Delphi в 2 раза медленнее чем версия на ASM из [11].
    Исходный объем: 676.24 Мб
    ASM - 2.69 секунды
    Pascal - 4.98 секунды
  • Sha © (27.02.17 22:16) [36]
    > dmk ©   (27.02.17 21:59) [35]
    > Но версия на Delphi в 2 раза медленнее чем версия на ASM из [11].

    Мне показалось, что была проблема с алгоритмом.
    И мне было интересно потратить немного времени на сам алгоритм.

    Но ты же понимаешь разницу между алгоритмом и реализацией?
    Я совсем не хочу тратить свое свободное время и переписывать его ASM.
  • dmk © (27.02.17 22:56) [37]
    Да я для NoUser написал :)
  • NoUser © (28.02.17 00:03) [38]
    > А ваша вообще не работает :)
    Я и не претендую.

    А вот твоя (и асм и делфи), в некоторые моменты, действительно 'не работает' ! ;))
  • dmk © (28.02.17 05:08) [39]
    У меня все работает. Вы ее применять не умеете ;)
 
Конференция "Основная" » Инструкция ANDN (asm64)
Есть новые Нет новых   [118652   +9][b:0.001][p:0.002]