xchg mem,reg

Тема в разделе "WASM.ASSEMBLER", создана пользователем Jin X, 13 дек 2017.

  1. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Как известно, инструкция xchg, оперирующая с памятью, занимается нехорошим делом: блокировкой шины. Иногда, конечно, это дело очень даже полезное, но гораздо чаще – нет.

    Давайте подумаем: чем можно заменить эту инструкцию (скажем, xchg [ecx],eax) для максимизации скорости?
    Конечно, первое, что приходит в голову – это:
    Код (ASM):
    1. mov edx,[ecx]
    2. mov [ecx],eax
    3. mov eax,edx
    Скорость взлетает ощутимо – проверено.
    Но! Тут используется дополнительный регистр! А если лишнего регистра нет? Что делать?

    Может, я откровенно туплю, но пока в голову не приходит ничего лучше, чем:
    Код (ASM):
    1. push eax
    2. push [ecx]
    3. pop eax
    4. pop [ecx]
    или
    Код (ASM):
    1. xadd [ecx],eax
    2. sub [ecx],eax
    Но второй вариант работает даже медленнее, чем первый (в цикле, по крайней мере)!!!

    Ах, да, есть же ещё:
    Код (ASM):
    1. xor eax,[ecx]
    2. xor [ecx],eax
    3. xor eax,[ecx]
    Он работает быстрее, чем xadd и чуть быстрее, чем push/pop в цикле (и тем более xchg), но скорость всё равно низкая...

    Задача №2 (усложнённая). Нам нужно обменять 2 элемента в памяти (а-ля xchg [ecx],[edx]). В распоряжении у нас максимум 1 регистр.
    То бишь такое не прокатит:
    Код (ASM):
    1. mov eax,[edx]
    2. mov ebx,[ecx]
    3. mov [edx],ebx
    4. mov [ecx],eax
    Тут, конечно, относительно быстрым будет:
    Код (ASM):
    1. mov eax,[ecx]
    2. xor eax,[edx]
    3. xor [edx],eax
    4. xor eax,[edx]
    5. mov [ecx],eax
    Но хочется большего!!!

    Покумекаем? :)

    p.s. Всяческие варианты с MMX/SSE/FPU (или каким-нибудь особенным набором инструкций) прошу не предлагать как основные решения. Как дополнительные – ну ок, сгодятся, хотя вариант наподобие первого (с 3-мя mov'ами) тут вполне очевиден.
     
    Последнее редактирование: 13 дек 2017
  2. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Хотя, кстати говоря, код...
    Код (ASM):
    1. fld dword ptr [ecx]
    2. fld dword ptr [edx]
    3. fstp dword ptr [ecx]
    4. fstp dword ptr [edx]
    ...довольно шустр! И работает быстрее варианта с xor :grin:
     
  3. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Подсказано с другого форума:
    Код (ASM):
    1. push [ecx]
    2. mov [ecx],eax
    3. pop eax
    Отличный вариант!
     
  4. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Обмен значений 2-х переменных:
    Код (ASM):
    1. push [ecx]
    2. mov eax,[edx]
    3. pop [edx]
    4. mov [ecx],eax
    p.s. Но почему-то вариант:
    Код (ASM):
    1. push [ebp-4]
    2. mov eax,[ebp-8]
    3. pop [ebp-8]
    4. mov [ebp-4],eax
    работает чуть быстрее... кто-нибудь может объяснить: почему?
    Это при том, что в первом случае я делаю lea ecx,[ebp-4] + lea edx,[ebp-8] (они не учитываются в замере скорости, я их даже не удаляю для второго варианта). И даже если я заменю ecx/edx на esi/edi и размещу эти lea до rdtscp (которая производит сериализацию), результат тот же: варианты с [ebp-...] быстрее!
     
    Последнее редактирование: 17 дек 2017
  5. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Ещё (про обмен регистра с памятью):
    Код (ASM):
    1. push eax
    2. mov eax,[ecx]
    3. pop [ecx]
    как будто бы немного быстрее работает (результаты тестов нестабильные, но ощущение такое)...
    И опять же, есть разница: используется ли именно [ecx] или [ebp-4].
     
  6. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Оптимизировал измерялку, получилось:
    Код (ASM):
    1. push [ecx]
    2. mov eax,[edx]
    3. mov [ecx],eax
    4. pop eax
    5. mov [edx],eax
    Быстрее (без цикла). И замена на [ebp-...] уже не влияет :)

    И код
    Код (ASM):
    1. push eax
    2. mov eax,[ecx]
    3. pop [ecx]
    получился ничуть не лучше, чем
    Код (ASM):
    1. push [ecx]
    2. mov [ecx],eax
    3. pop eax
     
  7. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Jin X,

    Можно было предсказать что профайл в этих случаях с заменой регистров должен быть одинаков, а ошибка в вашем профайлере. Так как это общий набор регистров(GPR) и без разницы эти замены, обработка их одинакова.
     
  8. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Это и удивляло.