Логическое значение у переменной

Тема в разделе "WASM.BEGINNERS", создана пользователем assch, 8 сен 2023.

  1. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    203
    Иногда нужно чтобы определённая переменная имела только логическое значение
    ноль или единица так называемое булево значение
    например при отработки какого нибудь алгоритма
    каждый раз у переменной менялось бы логическое значение

    это конечно можно сделать обычным условным ветвлением

    Код (ASM):
    1.  
    2. if dDword == 0
    3. mov dDword,1
    4. else
    5. mov dDword,0
    6. endif
    7.  
    этот способ условным ветвлением всегда даст нужный результат
    но поменять логическое значение можно и более быстрым способом

    Код (ASM):
    1.  
    2. xor dDword,1
    3.  
    но это будет работать только если у переменной ноль или единица
    по сути это конечно то что нам и нужно
    но если по какой то случайности в переменной будет другое значение
    этот способ не даст ожидаемого результата

    есть ли другой способ по мимо условного ветвления
    делать так чтобы если в переменной ноль
    в ней появлялось бы например любое не нулевое значение
    и соответственно если в переменной любое не нулевое значение
    в ней появлялся бы ноль

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

    Код (ASM):
    1.  
    2. cmp dByte,0
    3. setz dByte
    4.  
    но это работает только с однобайтовыми значениями

    для подобных логических переменных по сути и нужно использовать однобайтный тип
    по тому что для нуля или единицы четыре байта многовато будет

    но просто ради интереса
    есть ли другой способ по мимо условного ветвления у четырёх байтовых переменных

    кто в теме подскажите пожалуйста
     
  2. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    2.000
    Интересная конструкция, особенно когда в нуль помещается нуль. "test eax,eax" короче сравнения с нулем, "xor eax,eax/inc eax" короче помещения единицы. И как бы нуль в нуль помещать не надо.
    Код (Text):
    1. 8B45 FC    mov eax,dword ptr ss:[ebp-4]
    2. 85C0       test eax,eax
    3. 74 03      je @F
    4. 31C0       xor eax,eax
    5. 40         inc eax
    6. 8945 FC    mov dword ptr ss:[ebp-4],eax
    7.         @@:
    movzx - стопроцентный способ заполнить старшие биты нулями. Но возникает вопрос нафига такой длинный setne вооще нужен, если приведенный выше код короче.
    Код (Text):
    1. 8B45 FC mov eax,dword ptr ss:[ebp-4]
    2. 85C0    test eax,eax
    3. 74 06   je @F
    4. 0F95C0  setne al
    5. 0FB6C0  movzx eax,al
    6. 8945 FC mov dword ptr ss:[ebp-4],eax
    7.         @@:
    ЗЫ: если вместо нуля надо единицу, а при ненулевом значении нуль:
    Код (Text):
    1.  
    2.             mov eax,[boolValue]
    3.             test eax,eax
    4.             .if ~ZERO?
    5.                 xor eax,eax
    6.             .else
    7.                 inc eax
    8.             .endif
    9.             mov [boolValue],eax
     
    Последнее редактирование: 8 сен 2023
  3. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    203
    последний приведенный код конечно рабочий
    но только для его исполнения нужно использовать и соответственно испортить регистр - eax

    зачем это делать если можно обойтись без порчи регистра
    и просто поменять логическое значение у переменной
    применив банальное условное ветвление описанное самым первым

    Код (ASM):
    1.  
    2. if dDword == 0   ; если в переменной ноль
    3. mov dDword,1     ; прописываем в ней единицу
    4. else             ; если не ноль
    5. mov dDword,0     ; прописываем в ней ноль
    6. endif
    7.  
     
  4. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    2.000
    Ну как сказать. eax/ecx/edx - регистры, которые просто предназначены для обработки значений, а не долговременного хранения в них чего-то. Достаточно бегло посмотреть на набор инструкций проца или хотя бы на код, который нормальные компиляторы генерируют. Возможность выполнять ряд операций над значениями в памяти конечно существует, но как дополнительная фишка для большей гибкости. Если у тебя в любой момент времени нет свободного регистра для обработки, вероятно ты что-то делаешь неправильно и какое-то значение у тебя зря занимает регистр.
     
  5. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    203
    f13nd спасибо за участие
     
  6. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Код (ASM):
    1.  
    2. neg eax
    3. sbb eax, eax
    4. inc eax
    5.  
     
  7. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    603
    То есть нужен код A=!B сишный ?
    Код (ASM):
    1. cmp B,0
    2. setz al
    3. movzx A, al
    В С/С++ логическое значение выражения приводится к char т.е. к байту, точней логический бит минимально адресуемую байту, ну т.е. к слову. Жаль С/С++ не умеет работать с битами, видать слишком сложно реализовать на высокий кроссплатформенный уровень.
    Я обычно подсматриваю у компиляторов, изучаю код идой.
     
  8. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    458
    а как же std::bitset ?
    да и #include <bit> в С++20 много вкусняшек дает для бит-операций
     
  9. TrashGen

    TrashGen ТрещГен

    Публикаций:
    0
    Регистрация:
    15 мар 2011
    Сообщения:
    1.191
    Адрес:
    подполье
    норкоманы хочут необморфляемой jecXXX норкоманеи!^^
    Код (Text):
    1.  
    2.   .386
    3.    .model flat,stdcall
    4.    option casemap:none
    5. .data
    6. dDword dd 666 ; оргумент мегофункцыи нулевово тня
    7. ; выход - либо NULL, либо -1, ибо ололо и ваистенуЁ!
    8. .code
    9. @@:
    10. not dword ptr[dDword]
    11.  ; 0
    12. ret
    13.  
    14. start:
    15. xor ecx,ecx
    16. xchg dword ptr[dDword],ecx
    17. jecxz @b
    18.  ; !=0
    19. ret
    20. end start
    21.  
     
    Последнее редактирование: 9 сен 2023
  10. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    203
    спасибо за участие в теме
    в принципи я хотел сделать макрос например - logic
    с одним параметром что то типа

    Код (ASM):
    1.  
    2. logic dDword
    3.  
    где под капотом и прописывался бы нужный код

    рабочий код предложенный - rmn
    к сожелению для этого макроса не лучший вариант
    потому что придётся сначала кинуть значение переменной в регистр
    и соответственно в конце из регистра в переменную

    Код (ASM):
    1.  
    2. mov eax,dDword
    3. neg eax
    4. sbb eax,eax
    5. inc eax
    6. mov dDword,eax
    7.  
    и при замере скорости исполнения он в два раза уступает
    банальному условному ветвлению

    Код (ASM):
    1.  
    2. if dDword == 0
    3. mov dDword,1
    4. else
    5. mov dDword,0
    6. endif
    7.  
     
  11. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    153
    Код (ASM):
    1. sub eax,1
    2. sbb eax,eax
    с памятью
    Код (ASM):
    1. sub [dword],1
    2. mov eax,[dword]
    3. sbb [dword],eax
    о быстролействии современных процов говорить не прходится
    --- Сообщение объединено, 9 сен 2023 ---
    лучше
    Код (ASM):
    1. mov eax,[dword]
    2. cmp eax,1
    3. sbb [dword],eax
    И потом Neg XXX ко всем вариантам, плохо чего-то.
    тогда уж
    Код (ASM):
    1. cmp [dword],1 ; или sub
    2. Mov [dword],0
    3. AdC [dword],0
    --- Сообщение объединено, 9 сен 2023 ---
    вместо AdC [dword],0 можно RCL [dword],1
    --- Сообщение объединено, 9 сен 2023 ---
    А так же SetC Byte ptr [dWord]
    --- Сообщение объединено, 9 сен 2023 ---
    И ваше первое выглядит хорошо:
    Сmp [dWord],0
    Mov [dWord],0
    SetZ Byte ptr [dWord]
     
  12. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    203
    R81..., спасибо за варианты
    попробую по тестить
    --- Сообщение объединено, 9 сен 2023 ---
    думаю что если для логического значения будет использоваться переменная
    1-байтовая или 2-байтовая или 4-байтовая
    Код (ASM):
    1.  
    2. logic переменная
    3.  
    под капотом буду прописывать
    Код (ASM):
    1.  
    2. cmp переменная,0
    3. mov переменная,0
    4. setz byte ptr [переменная]
    5.  
    если для логического значения будет использоваться регистр
    8-разрядный или 16-разрядный или 32-разрядный
    Код (ASM):
    1.  
    2. logic регистр
    3.  
    под капотом буду прописывать
    Код (ASM):
    1.  
    2. cmp регистр,1
    3. mov регистр,0
    4. adc регистр,0
    5.  
    R81 ещё раз спасибо за варианты

    Век живи век учись
     
  13. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    153
    Код (ASM):
    1. cmp переменная,0
    2. setz byte ptr [переменная]
    3. and [переменная],1
    на три байта короче

    а так медленно?
    Cmp eRx,1
    RCR eRx,1
    And eRx,1
    --- Сообщение объединено, 9 сен 2023 ---
    Исправляю ошибку
    Cmp eRx,1
    RCL eRx,1 ; так правильно
    And eRx,1
    Или
    Cmp eRx,1
    RCR eRx,1
    SHR eRx,31
    --- Сообщение объединено, 9 сен 2023 ---
    Исправляю ошибку - для макро лучше
    Cmp eRx,1 ; можно и Neg eRx
    RCR eRx,1
    SHR eRx,-1
    Также не понятно почему код rmn
     
  14. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    203
    R81..., при замере скорости не факт но скорее всего была допущена не точность
    сейчас честно говоря времени нет а вот завтра утром попробую ещё раз по тестить

    очень благодарен за участие
     
  15. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    203
    можно сделать определённый вывод

    если в качестве логического значения использовать
    только 1-байтную переменную или 8-разрядный регистр то проблем ни каких нет
    потому что для этого можно использовать универсальный алгоритм
    независимо от того переменная это или регистр без разницы

    cmp dByte,0
    setz dByte

    или

    cmp al,0
    setz al

    например в языке Си так и поступают
    там для булево значения используют только 1-байтную переменную
    которая имеет соответствующий тип - Bool
    она может принимать только два значения ноль или единица
    и при попытки поместить туда значение больше единицы
    там применяется этот алгоритм описанный выше
    который соответственно заточен только на ноль или единицу

    но если для логического значения
    использовать широкий спектр переменных или регистров
    то универсальным алгоритмом для этого будет этот предложенный код

    cmp eax,1
    mov eax,0
    adc eax,0

    чтобы не занимать много места пример показан с регистром - eax
    но вместо него можно подставить регистр другой разрядности
    или любую другую разрядную переменную

    например тоже хороший код предложенный - rmn

    neg eax
    sbb eax,eax
    inc eax

    отработает только с регистрами

    прошу прощения что написал что он в два раза уступает
    банальному условному ветвлению я просто не правильно подставил данные

    теперь что касается замера скорости исполнения
    я её конечно точно измерить не могу
    хотя может быть я что то не так делаю
    буду признателен если кто то предложит что то другое

    я например использую вот этот алгоритм

    mov ebx,4000000000
    @Tick
    while ebx
    ;--------------------
    сюда вставляется тестируемый код
    ;--------------------
    dec ebx
    endw
    @Tick

    я думаю интуитивно всё должно быть понятно
    количество раз исполнения изначально закладывается в регистр - ebx
    при трудных алгоритмах лучше обрезать последние нули у этого регистра
    а то можно очень долго ждать результата

    @Tick - это по сути макрос

    под капотом которого при старте записывается начальное время
    а в конце высчитывается время исполнения
    и результат выводится в месаждбокс в миллисекундах

    ещё раз повторю что точного замера не получится
    и при повторном прогоне значение может плавать
    наверное это зависит от загруженности процессора на данный момент времени

    но если прогнать определённый алгоритм например три раза подряд
    можно отметить определённое наименьшее значение
    и соответственно если прогнать так же другой алгоритм
    можно будет определить разницу значений
    и соответственно понять что какой то алгоритм работает быстрее другого
    или можно сделать вывод что по сути особой разницы нет

    кстати говоря насчёт меньшего байт-кода алгоритма обольщаться не надо
    иногда большой байт-код алгоритма выполняется быстрее иногда даже в разы
    чем алгоритм с меньшим байт-кодом

    всё зависит наверное от количества тиков процессора
    при выполнении определённой команды
    хотя может быть и от очерёдности команд для процессора тоже что значит

    протестируем банальное ветвление
    и перед каждым разом будем инициализировать переменную

    mov dDword,1
    if dDword == 0
    mov dDword,1
    else
    mov dDword,0
    endif

    наименьшее значение в миллисекундах - 5865

    теперь тестируем универсальный алгоритм с переменной

    mov dDword,1
    cmp dDword,1
    mov dDword,0
    adc dDword,0

    наименьшее значение в миллисекундах - 3947

    теперь тестируем тот же универсальный алгоритм но уже с регистром

    mov eax,1
    cmp eax,1
    mov eax,0
    adc eax,0

    наименьшее значение в миллисекундах - 2917

    а если применить алгоритм только для переменных

    mov dDword,1
    cmp dDword,0
    mov dDword,0
    setz byte ptr [dDword]

    наименьшее значение в миллисекундах - 3464

    отсюда вывод что для моего макроса
    мне нужно применить или универсальный метод для переменных или регистров
    или всё же если в качестве логического значения будет использоваться регистр
    под капотом прописывать

    cmp eax,1
    mov eax,0
    adc eax,0

    а если в качестве логического значения будет использоваться переменная
    под капотом прописывать

    cmp dDword,0
    mov dDword,0
    setz byte ptr [dDword]

    универсальный алгоритм конечно же хорошо но думаю выберу раздельный вариант

    кстати говоря свой макрос я не буду делать макро-средствами - masm32

    однажды на основе своих макросов я делал один проект по - OpenGL
    которые конечно же очень сильно упрощали написание рутинного кода
    но я обратил внимание что время сборки проекта было - 2000 миллисекунд
    то есть около двух секунд не критично конечно но мягко говоря не радовало

    я понял что компилятор сначала обрабатывает мои макросы которых было не мало
    и только потом приступает к основному прогону проекта

    я подумал а что если написать транслятор и компиляцию делать в два этапа
    сначала транслятор переписывает мой код проекта на синтаксис - Ассемблера
    и потом соответственно этот код обрабатывает основной компилятор - Ml.exe
    я тайно надеялся что время сборки проекта будет хотя бы в два раза меньше
    про большее я и не мечтал но результат превзошёл все мои ожидания
    время сборки этого же проекта упала в 20 раз и стала - 100 миллисекунд

    с тех пор как не трудно догадаться
    я давно забыл про макросы и пользуюсь своим транслятором
     
    Последнее редактирование: 10 сен 2023
    R81... нравится это.
  16. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    875
    Для разовых сравнений эти микрооптимизации практически незаметны. Можно ещё заюзать CMOV после MOV. Вообще на больших объёмах данных гораздо быстрее заюзать SIMD где можно сразу несколько таких операций сделать - вот тут как раз и будет преимущество в скорости + можно это сделать 1 инструкцией PCMPEQD.
     
    Marylin нравится это.
  17. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    153
    Я это называю PreAsm (преассемблер или предассемблер), но никак не возьмусь написать, но это скорее: МойКодXC166>PreAsmCrossForFasm>Fasm> XC166(.bin).
    Повозился с FasmG - не понравилось.

    Параллельность - да.
    1. MоvXXX ...; 0 в регистры придется загрузить
    2 PCMPEQD ^^^^^^^^^,память ; "элемент заполняется единицами"
    3 And ...; 0...01, в регистрах-то все 1111
    4 MovXXX....; из регистров в память.
    Итого
    ??
     
  18. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    203
    если кому интересно даю ссылку для примера на один мой проект
    под названием - Меню с подсказками и шевронами
    этот проект я делал кажется пять лет назад когда наткнулся в интернете
    на статью - Создание строки меню в стиле Internet Explorer
    если в поиске набрать эти строки скорее всего найдёте её

    файл заархивирован паролем - 123
    он лежит у меня на облачном хранилище

    https://cloud.mail.ru/public/bULg/PVu3LQLiA

    если запустить исполняемый файл то откроется окно с кнопками меню
    и кнопками контрола - ребара
    верхнии кнопки меню это тоже по сути - ребар
    если поводить курсором по строкам меню
    можно увидеть как они окрашиваються в стиле - Internet Explorer

    если нажать на меню - Вид
    и в ниспадающем меню нажать на - Простое меню
    то кнопки меню приобретут обычный стиль
    если снять эту галку то меню станет прежним

    если в том же меню - Вид
    нажать на - Открепить меню
    у каждого ребара в левой стороне специально откроются вертикальные точки
    и если захватить эти точки мышкой можно перетащить ребар в другое место
    если в ребаре с кнопкой с чёрным квадратом открыть его меню
    то вабрав цвет можно перекрасить эту кнопку

    остальные кнопки просто подключены к звуковым сигналам

    если потащить окно мышкой за левый край окна и сделать окно меньше по ширине
    то дойдя до меню будут показыватся шевроны
    предназначение которых я думаю интуитивно понятно

    по сути проект заточен только для показа ребаров с меню с кнопками и шевронами
    делал я этот проект исключительно ради интереса

    если открыть файл картинку - tst.bmp
    то там можно увидеть какие исполняемые файлы участвуют в сборке проекта
    ну и время потраченное ими а в конце показано общее время сборки

    если посмотреть файлы проекта то можно увидеть что стиль синтаксиса
    в определённых случаях отличается от стиля платформы - masm32
    для этого и создавался транслятор который бы переписывал кодинг проекта
    под чистый синтаксис - masm32

    папка с решёткой - #
    это рабочая папка проекта
    и если её открыть то можно увидеть в ней файл - $.asm

    в этом файле и будет находится переписанный синтаксис проекта
    который и обрабатывает следующим этапом основной компилятор - Ml.exe
    и соответственно в этом файле можно посмотреть во что трансфрмировался
    непривычный основной синтаксис проекта

    но в любом случае это конечно только для любопытных

    а эту тему я создал для того чтобы научить свой транслятор
    еще одной по сути команде - logic

    если кому интересно по тематике транслятора
    можно писать на почту - assch@list.ru
     
    Последнее редактирование: 10 сен 2023
  19. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    875
    Ну PCMPEQD сделает это:
    Если в mm/xmm слоте 0 при сравнении с 0 там будут единицы, иначе нули. Только таких операций будет выполнено сразу несколько одновременно.