Русский / Russian English / Английский

Сейчас на форуме: bartolomeo (+1 невидимый пользователь)
 · Начало · Статистика · Регистрация · Поиск · ПРАВИЛА ФОРУМА · Язык · RSS ·

 eXeL@B —› Программирование —› Заменить старший байт
Посл.ответ Сообщение

Ранг: 18.9 (новичок)
Статус: Участник

Создано: 14 марта 2020 00:52 · Поправил: Ate New!
Цитата · Личное сообщение · #1

Нужна была функция для преобразования значения цвета BGR <-> RGB с принудительной установкой альфы, написал так:

Code:
  1. mov dword eax, Color
  2. bswap eax
  3. ror eax, 8
  4.  
  5. ; принудительная установка альфы в 255
  6. ror eax, 24
  7. mov al, 0xFF
  8. rol eax, 24


почему-то думаю можно как-то проще заменить старший байт (последние три инструкции)




Ранг: 568.2 (!)
Статус: Участник
оптимист

Создано: 14 марта 2020 01:10 New!
Цитата · Личное сообщение · #2

Code:
  1. OR EAX,0FF0

?

| Сообщение посчитали полезным: Ate


Ранг: 158.6 (ветеран)
Статус: Участник

Создано: 14 марта 2020 01:30 New!
Цитата · Личное сообщение · #3

Code:
  1. shl eax, 8
  2. mov al, 0xFF
  3. bswap eax

| Сообщение посчитали полезным: Ate


Ранг: 18.9 (новичок)
Статус: Участник

Создано: 14 марта 2020 02:05 New!
Цитата · Личное сообщение · #4

Спасибо, то что нужно.



Ранг: 13.2 (новичок)
Статус: Участник

Создано: 14 марта 2020 03:24 New!
Цитата · Личное сообщение · #5

ClockMan пишет:
OR EAX,0FF0

Почему маска странная? Опечатка?



Ранг: 63.5 (постоянный)
Статус: Участник

Создано: 14 марта 2020 05:37 New!
Цитата · Личное сообщение · #6

Вообще то какбэ or eax, 0xFF000000



Ранг: 18.9 (новичок)
Статус: Участник

Создано: 19 мая 2020 20:56 New!
Цитата · Личное сообщение · #7

Аналогичный вопрос по возможности оптимизировать конструкцию вида:

Code:
  1. ; Читаем из таймера значение в 100нс интервалах, преобразуем в мс и сохраняем в 'time'
  2. mov rbp, qword [timer]
  3. mov r15, qword [rbp]
  4. mov rax, r15
  5. mov rcx, 10000
  6. cqo
  7. idiv rcx
  8. mov r15, rax
  9. mov qword [time], r15


Поскольку 10k не является степенью двойки, заменить деление битовым сдвигом вроде как не получается, мб умножением?
И еще хотел уточнить, как в данном варианте происходит округление при делении, нужно ли добавлять код для "Round to nearest"?



Ранг: 419.0 (мудрец)
Статус: Участник
"Тибериумный реверсинг"

Создано: 19 мая 2020 23:05 · Поправил: ELF_7719116 New!
Цитата · Личное сообщение · #8

Как минимум, можно обойтись без r15 и rbp
Code:
  1. mov rax, qword [timer]
  2. mov rcx, 10000
  3. cqo
  4. idiv rcx
  5. mov qword [time], rax

| Сообщение посчитали полезным: Ate



Ранг: 568.2 (!)
Статус: Участник
оптимист

Создано: 20 мая 2020 01:34 New!
Цитата · Личное сообщение · #9

SAR RAX, 0x10



Ранг: 63.5 (постоянный)
Статус: Участник

Создано: 20 мая 2020 03:22 New!
Цитата · Личное сообщение · #10

Там же десятичное 10к



Ранг: 173.8 (ветеран)
Статус: Участник

Создано: 20 мая 2020 03:44 · Поправил: VOLKOFF New!
Цитата · Личное сообщение · #11

ELF_7719116 пишет:
Как минимум, можно обойтись без r15 и rbp

Тут судя по коду **timer а не *timer и в твоем варианте мы читаем в RAX адрес указателя а не значение
Хотя предпоследняя и вторая строки явно лишние, можно заменить на mov rax, qword [rbp] и mov qword [time], rax соответственно, избавившись от r15

ClockMan пишет:
SAR RAX, 0x10

А даст ли sar нужный результат при делителе не 2ⁿ...

Ate пишет:
как в данном варианте происходит округление при делении, нужно ли добавлять код для "Round to nearest"?

Целочисленное частное округляется в сторону нуля.
Я бы вообще не стал заморачиваться с округлением, если не нужна точность меньше* 1мс
В ином случае можно заюзать FPU (у которого дефолтный режим округления как раз к ближайшему),
fld+fistp, или cvtss2si (если режим не изменен)
но проще проверять остаток деления и соответственно корректировать результат.

Можно вместо деления умножать на 0.0001, но тогда все придется делать на фпу, хотя работать будет быстрее ~x2

| Сообщение посчитали полезным: Ate


Ранг: 63.5 (постоянный)
Статус: Участник

Создано: 20 мая 2020 05:45 New!
Цитата · Личное сообщение · #12

VOLKOFF пишет:
Целочисленное частное округляется в сторону нуля

Там знаковое деление, для отрицательных чисел, насколько я понимаю, с точностью до наоборот



Ранг: 173.8 (ветеран)
Статус: Участник

Создано: 20 мая 2020 21:42 New!
Цитата · Личное сообщение · #13

_MBK_ пишет:
для отрицательных чисел, насколько я понимаю, с точностью до наоборот


Intel® 64 and IA-32 Software Developer’s Manuals 2019
The quotient from the IDIV instruction is rounded toward zero, whereas the “quotient” of the SAR instruction is
rounded toward negative infinity. This difference is apparent only for negative numbers. For example, when the
IDIV instruction is used to divide -9 by 4, the result is -2 with a remainder of -1. If the SAR instruction is used to
shift -9 right by two bits, the result is -3 and the “remainder” is +3; however, the SAR instruction stores only the
most significant bit of the remainder (in the CF flag)


IDIV_-5:2=-2
IDIV__5:2= 2

...-2,5...-2...0...2...2,5...

Вроде все логично.



Ранг: 18.9 (новичок)
Статус: Участник

Создано: 20 мая 2020 22:24 New!
Цитата · Личное сообщение · #14

Спасибо за ответы!
Действительно, можно же на 0.0001 умножать и тактов меньше уходит.
Сделал так (double factor = 0.0001)
Code:
  1. mov rax, [timer]
  2. fild qword [rax]
  3. fmul [factor]
  4. fistp  [time]


Насколько понимаю, результат fistp зависит от битов 14 и 13 регистра MXCSR.
Если я в коде не менял режима, насколько высока вероятность, что он будет не стандартным, имеет смысл его проставлять (и если да, как покороче это сделать)?



Ранг: 73.1 (постоянный)
Статус: Участник

Создано: 20 мая 2020 22:46 · Поправил: RamMerlabs New!
Цитата · Личное сообщение · #15

MXCSR для SIMD floating-point же.
Для простого x87 FPU будет CW - 10 и 11 биты для Ваших целей. Как-то так:
Code:
  1. wControlWord WORD ?
  2.  
  3. fstcw wControlWord
  4. or wControlWord, 0C00h
  5. fldcw wControlWord

| Сообщение посчитали полезным: Ate


Ранг: 63.5 (постоянный)
Статус: Участник

Создано: 21 мая 2020 01:35 · Поправил: _MBK_ New!
Цитата · Личное сообщение · #16

VOLKOFF пишет:

Вроде все логично

Логичен был бы эквивалент round - число= частное×делитель+остаток, но, по сути таки да, получается, что везде делят по модулю и дописывают знак, т.е. и на отрицательных выравнивает к нулю



Ранг: 13.2 (новичок)
Статус: Участник

Создано: 21 мая 2020 13:49 New!
Цитата · Личное сообщение · #17

просто деление edi на 10000, быстро, ret result in eax:

divide_by_10k(int edi):
movsx rax, edi
imul rax, rax, 1759218605
sar rax, 44
sar edi, 31
sub eax, edi
ret

;)



Ранг: 73.1 (постоянный)
Статус: Участник

Создано: 21 мая 2020 22:10 · Поправил: RamMerlabs New!
Цитата · Личное сообщение · #18

friend
Выше речь идёт о делении 64-битного значения, соответственно конкретно эта реализация не подойдёт - rdx из пары rdx:rax после imul никак не обрабатывается, но с большой вероятностью будет задействован (т.е. нужен "обычный" вариант imul с одним операндом)
PS: И с "магическими" константами нужно быть осторожным - не все комбинации из умножения на такую константу и сдвига дадут точный результат на всём диапазоне аргументов, даже в пределах [0...2^32).



Ранг: 13.2 (новичок)
Статус: Участник

Создано: 22 мая 2020 00:06 New!
Цитата · Личное сообщение · #19

x64div:
movabs rdx, 3777893186295716171
mov rax, rdi
sar rdi, 63
imul rdx
sar rdx, 11
mov rax, rdx
sub rax, rdi
ret

> PS: И с "магическими" константами нужно быть осторожным - не все комбинации из умножения на такую константу и сдвига дадут точный результат на всём диапазоне аргументов, даже в пределах [0...2^32).
Ты sub забыл. Погугли что за трюк. Я ведь не от руки/головы этот код пишу, godbolt ftw ;)

Also, Hackers Delight, Chapter 10. Integer Division By Constants

https://stackoverflow.com/questions/36039509/why-does-the-0x55555556-divide-by-3-hack-work

Если я ошибаюсь то пиши где алго не точен.



Ранг: 73.1 (постоянный)
Статус: Участник

Создано: 22 мая 2020 01:18 New!
Цитата · Личное сообщение · #20

friend
Не забыл, "трюк" этот достаточно давно известен, суть алгоритма замены деления аналогичная везде - mul+shr/sar+sub.
Хоть упоминай sub, хоть нет, переполнение rax при умножении заведомо немаленького числа (напомню, речь в задаче идёт о счётчике "тиков") на 0x68DB8BAD более чем вероятно

Я не говорю, что конкретно это "магическая" константа для замены деления на конкретно этот делитель приведёт к неточному результату, а в целом о подходе. емнип, на форуме masm32 это обсуждалось и приводились примеры тестирования для разных констант, демонстрирующие, что не вся "магия" одинаково полезна.



Ранг: 173.8 (ветеран)
Статус: Участник

Создано: 22 мая 2020 02:53 · Поправил: VOLKOFF New!
Цитата · Личное сообщение · #21

Вариант имеет место быть, но выигрыша в скорости, или краткости конструкции перед выбранным ТС подходом у него нет, а вот недостаток (с позиции запроса ТС) есть - отсутствие округления результата к ближайшему целому.

Кстати "о птичках"
RamMerlabs пишет:
or wControlWord, 0C00h


Rounding Modes and Encoding of Rounding Control (RC) Field:
RC: . Rounding Mode:
00b - Round to nearest (even) Default!
01b - Round down (toward −∞)
10b - Round up (toward +∞)
11b - Round toward zero (Truncate)


!or [CWR], 0000110000000000b ; (0C00h) приведет к Round toward zero (Truncate)

Для Round to nearest нужно

!and [CWR], 0xf3ff ; 1111001111111111b

Или еще можно сбросить в дефолт через finit, флаш пайплайна так и так будет (из-за fldcw в изначальном варианте)
Если код будет в цикле, достаточно перед ним (или в начале функции) вызвать один раз. Маловероятно, но стоит убедится что сброс остальных флагов не повлияет на логику программы:

FINIT/FNINIT инициализация сопроцессора (установка значений в 037Fh)
RC = 00b ; округление к ближайшему целому
PM,UM,OM,ZM,DM,IM = 1 ; все исключения не замаскированы
PC = 11b ; максимальная точность 64 бита (даже если при старте программы было установлено 10b)
SWR = 0h ; отсутствие исключений и указание на то, что r0 является вершиной стека и соответствует ST(0)
TWR = FFFFh ; все регистры стека сопроцессора пусты
DPR = 0
PR = 0


PS
LinXP, спасибки, работает

| Сообщение посчитали полезным: Ate


Ранг: 13.2 (новичок)
Статус: Участник

Создано: 23 мая 2020 15:30 · Поправил: friend New!
Цитата · Личное сообщение · #22

RamMerlabs пишет:
Хоть упоминай sub, хоть нет, переполнение rax

Переполнения rax из принципа быть не может, трюк этот для деления на константы и так как в задаче делят на 10к то тут всё однозначно.
-edit-
То есть "переполнение" есть но оно не играет роли.

Насчёт скорости не верю что подымать фпу и трогать мем быстрее даже в цикле. Бэнчи в студию.

-edit-
unsigned, even shorter

xdiv(unsigned long long):
movabs rdx, 3777893186295716171
mov rax, rdi
mul rdx
mov rax, rdx
shr rax, 11
ret

| Сообщение посчитали полезным: Ate


Ранг: 18.9 (новичок)
Статус: Участник

Создано: 26 мая 2020 09:57 · Поправил: Ate New!
Цитата · Личное сообщение · #23

Спасибо!

Столкнулся еще с одним интересным вопросом.
Есть структура размером 8 байт, как я понимаю безопасно считать это значение из другого потока я могу только под х64 например обычным mov, под х32 нужна атомарная операция среди которых для работы с QUAD подходит только LOCK CMPXCHG8B и у нее есть особенность расположения данных в EDX:EAX и ECX:EBX

Code:
  1. mov dword eax, mem
  2. mov dword edx, mem+4
  3. lock cmpxchg8b [dest]


Есть ли возможность под х32 поместить в EDX:EAX значение из памяти одной командой?
И вообще не усложняю ли я реальное положение дел?



Ранг: 173.8 (ветеран)
Статус: Участник

Создано: 26 мая 2020 12:56 New!
Цитата · Личное сообщение · #24

Ate пишет:
не усложняю ли я

Однозначно.
По основным пунктам ты безусловно мыслишь верно, но сравнение с обменом в таком контексте обойдется слишком дорого, поэтому имхо лучше так не делать.
MOVQ - вполне себе атомарно
MOVLPS
FILD/FSTP


Вот --> живые примеры <--

| Сообщение посчитали полезным: Ate

 eXeL@B —› Программирование —› Заменить старший байт

Видеокурс ВЗЛОМ