-
Я так понял, что ANDN (Logical AND NOT) инструкция не поддерживается Delphi? У меня XE6. Компилятор говорит Undeclared identifier.
-
нет конечно, ибо BMI1. (как и TZCNT) Она практически никакими декомпилерами не поддерживается. А AND + NOT использовать не судьба?
-
blsr, blsi, blsmsk тоже не поддерживает :( короче инструкции bmi1 и dmi2 в Delphi отсутствуют.
-
>А AND + NOT использовать не судьба? Мне байт надо превратить в 64 бита. Не знаю как лучше сделать. короче есть байт 10101111b, а нужно из него сделать FF00FF00FFFFFFFFh У меня сейчас таблица зарнее расчитана 8 -> 64, но очень медленно получается из памяти читать.
-
Сейчас через таблицу[0..255] работает:
mov rdx, TableAddr movzx eax, byte ptr [rsi] shl ax, 3 //Смещение в таблице mov rax, [rdx+rax] //Читаем строку байтов mov [rdi], rax //Пишем готовую строку
Думал быстрее сделать.
-
> dmk © (20.02.17 10:16) [4]
Чет я слегка прифигел, нукась дай ка мне саму таблицу.
-
По описанию вроде bextr подходит, но она тоже bmi1 :(
-
Таблица расчитывается. Так не выложишь ;)
//Процедура создает массив отображающий биты в 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;
-
Вернее таблица занимает 2Кб
-
Вот чесно говоря ничего не понятно :) Покажи процедуру с асмом полностью, ибо вот после этого:
movzx eax, byte ptr [rsi] ... mov rax, [rdx+rax] //Читаем строку байтов без xor rax, rax имеешь шанс вылететь в трубу
еще не понятно откуда RSI приходит
-
хотя нет, про RAX это лишнее
-
Преобразует биты в байты: 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;
-
Ну в принципе норм. только вот так бы вот начало переписал:
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-представления битов
-
а, блин, за вот такое руки бы оторвать: movq xmm0, rsi movq xmm1, rdi movq xmm2, rbx
у тебя чего стека нема? А если у меня там Extended лежит промежуточный?
-
Не, там ничего не лежит. Со стеком медленнее работает. Память все таки.
Есть такой вариант, но он медленнее в 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;
-
>А если у меня там 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 всегда свободны. Потому и использую как стек. Быстрее все рабоатет.
-
имбаркадеро вообще память копирует через FPU. Ничего - работает :)
-
Да, это я уже заработался, у меня половина защиты через XMM и DR регистры выстроена. Ошибся.
-
Интересно, а как собрать самому последовательность?
Кое что прочитал, но пока не понял как инструкцию собрать ;(
//Наследственные префиксы 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
-
ну как в обычном ассемблирующем движке, у тебя даже REX префикс обозначен
-
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 и дальше куда регистры впихнуть непонятно ;) ПОСЛЕ или В имеющийся байт-код.
-
Если я правильно помню опкоды, (дельфи под руками нет) то влетишь на ILLEGAL_INSTRUCTION
-
-
ЗЫ не забудь, что у тебя 64 бита - значит REX префикс правильно выставь
-
Есть ещё PANDN, которая для SIMD, её Дельфи понимает.
-
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;
-
Можно и в одну строчку, только очень длинную )
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;
-
если нужен NOT, то надо заменить
xor $8141211109050301
на
or $0101010101010100
-
более короткий вариант:
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;
-
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;
-
> У меня сейчас таблица зарнее расчитана 8 -> 64, > но очень медленно получается из памяти читать.
ну, читай из облака или алгоритм меняй ))
проблема может быть в том, что твои 20 ядер (на самом деле 10 плюс HT, который тут не нужен) 'уродуют' кэш или у тебя с выравниванием проблемы.
-
>алгоритм меняй Дык не работает BIM1,2 в дельфи.
-
я от том, что замена одного чтения (из 2 чтений и 1 записи) на одну лог операцию ( чтение bim запись) тебя сильно не спасёт.
тестер уже есть - замени bim, например, на xor - посмотри прирост в сравнении с таблицой (для одного потока, для многих )
-
Немного ускорил преобразование:
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;
-
>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;
Инициализация таблицы не критична. Там микросекунды и это при загрузке происходит. А ваша вообще не работает :)
-
Но версия на Delphi в 2 раза медленнее чем версия на ASM из [11]. Исходный объем: 676.24 Мб ASM - 2.69 секунды Pascal - 4.98 секунды
-
> dmk © (27.02.17 21:59) [35] > Но версия на Delphi в 2 раза медленнее чем версия на ASM из [11].
Мне показалось, что была проблема с алгоритмом. И мне было интересно потратить немного времени на сам алгоритм.
Но ты же понимаешь разницу между алгоритмом и реализацией? Я совсем не хочу тратить свое свободное время и переписывать его ASM.
-
Да я для NoUser написал :)
-
> А ваша вообще не работает :) Я и не претендую.
А вот твоя (и асм и делфи), в некоторые моменты, действительно 'не работает' ! ;))
-
У меня все работает. Вы ее применять не умеете ;)
|