Иногда нужно чтобы определённая переменная имела только логическое значение ноль или единица так называемое булево значение например при отработки какого нибудь алгоритма каждый раз у переменной менялось бы логическое значение это конечно можно сделать обычным условным ветвлением Код (ASM): if dDword == 0 mov dDword,1 else mov dDword,0 endif этот способ условным ветвлением всегда даст нужный результат но поменять логическое значение можно и более быстрым способом Код (ASM): xor dDword,1 но это будет работать только если у переменной ноль или единица по сути это конечно то что нам и нужно но если по какой то случайности в переменной будет другое значение этот способ не даст ожидаемого результата есть ли другой способ по мимо условного ветвления делать так чтобы если в переменной ноль в ней появлялось бы например любое не нулевое значение и соответственно если в переменной любое не нулевое значение в ней появлялся бы ноль например если для подобной логики использовать однобайтовую переменную то в данном случае есть сто процентный способ который тоже выполнится чуть быстрее чем условное ветвление Код (ASM): cmp dByte,0 setz dByte но это работает только с однобайтовыми значениями для подобных логических переменных по сути и нужно использовать однобайтный тип по тому что для нуля или единицы четыре байта многовато будет но просто ради интереса есть ли другой способ по мимо условного ветвления у четырёх байтовых переменных кто в теме подскажите пожалуйста
Интересная конструкция, особенно когда в нуль помещается нуль. "test eax,eax" короче сравнения с нулем, "xor eax,eax/inc eax" короче помещения единицы. И как бы нуль в нуль помещать не надо. Код (Text): 8B45 FC mov eax,dword ptr ss:[ebp-4] 85C0 test eax,eax 74 03 je @F 31C0 xor eax,eax 40 inc eax 8945 FC mov dword ptr ss:[ebp-4],eax @@: movzx - стопроцентный способ заполнить старшие биты нулями. Но возникает вопрос нафига такой длинный setne вооще нужен, если приведенный выше код короче. Код (Text): 8B45 FC mov eax,dword ptr ss:[ebp-4] 85C0 test eax,eax 74 06 je @F 0F95C0 setne al 0FB6C0 movzx eax,al 8945 FC mov dword ptr ss:[ebp-4],eax @@: ЗЫ: если вместо нуля надо единицу, а при ненулевом значении нуль: Код (Text): mov eax,[boolValue] test eax,eax .if ~ZERO? xor eax,eax .else inc eax .endif mov [boolValue],eax
последний приведенный код конечно рабочий но только для его исполнения нужно использовать и соответственно испортить регистр - eax зачем это делать если можно обойтись без порчи регистра и просто поменять логическое значение у переменной применив банальное условное ветвление описанное самым первым Код (ASM): if dDword == 0 ; если в переменной ноль mov dDword,1 ; прописываем в ней единицу else ; если не ноль mov dDword,0 ; прописываем в ней ноль endif
Ну как сказать. eax/ecx/edx - регистры, которые просто предназначены для обработки значений, а не долговременного хранения в них чего-то. Достаточно бегло посмотреть на набор инструкций проца или хотя бы на код, который нормальные компиляторы генерируют. Возможность выполнять ряд операций над значениями в памяти конечно существует, но как дополнительная фишка для большей гибкости. Если у тебя в любой момент времени нет свободного регистра для обработки, вероятно ты что-то делаешь неправильно и какое-то значение у тебя зря занимает регистр.
То есть нужен код A=!B сишный ? Код (ASM): cmp B,0 setz al movzx A, al В С/С++ логическое значение выражения приводится к char т.е. к байту, точней логический бит минимально адресуемую байту, ну т.е. к слову. Жаль С/С++ не умеет работать с битами, видать слишком сложно реализовать на высокий кроссплатформенный уровень. Я обычно подсматриваю у компиляторов, изучаю код идой.
норкоманы хочут необморфляемой jecXXX норкоманеи!^^ Код (Text): .386 .model flat,stdcall option casemap:none .data dDword dd 666 ; оргумент мегофункцыи нулевово тня ; выход - либо NULL, либо -1, ибо ололо и ваистенуЁ! .code @@: not dword ptr[dDword] ; 0 ret start: xor ecx,ecx xchg dword ptr[dDword],ecx jecxz @b ; !=0 ret end start
спасибо за участие в теме в принципи я хотел сделать макрос например - logic с одним параметром что то типа Код (ASM): logic dDword где под капотом и прописывался бы нужный код рабочий код предложенный - rmn к сожелению для этого макроса не лучший вариант потому что придётся сначала кинуть значение переменной в регистр и соответственно в конце из регистра в переменную Код (ASM): mov eax,dDword neg eax sbb eax,eax inc eax mov dDword,eax и при замере скорости исполнения он в два раза уступает банальному условному ветвлению Код (ASM): if dDword == 0 mov dDword,1 else mov dDword,0 endif
Код (ASM): sub eax,1 sbb eax,eax с памятью Код (ASM): sub [dword],1 mov eax,[dword] sbb [dword],eax о быстролействии современных процов говорить не прходится --- Сообщение объединено, 9 сен 2023 --- лучше Код (ASM): mov eax,[dword] cmp eax,1 sbb [dword],eax И потом Neg XXX ко всем вариантам, плохо чего-то. тогда уж Код (ASM): cmp [dword],1 ; или sub Mov [dword],0 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]
R81..., спасибо за варианты попробую по тестить --- Сообщение объединено, 9 сен 2023 --- думаю что если для логического значения будет использоваться переменная 1-байтовая или 2-байтовая или 4-байтовая Код (ASM): logic переменная под капотом буду прописывать Код (ASM): cmp переменная,0 mov переменная,0 setz byte ptr [переменная] если для логического значения будет использоваться регистр 8-разрядный или 16-разрядный или 32-разрядный Код (ASM): logic регистр под капотом буду прописывать Код (ASM): cmp регистр,1 mov регистр,0 adc регистр,0 R81 ещё раз спасибо за варианты Век живи век учись
Код (ASM): cmp переменная,0 setz byte ptr [переменная] 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
R81..., при замере скорости не факт но скорее всего была допущена не точность сейчас честно говоря времени нет а вот завтра утром попробую ещё раз по тестить очень благодарен за участие
можно сделать определённый вывод если в качестве логического значения использовать только 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 миллисекунд с тех пор как не трудно догадаться я давно забыл про макросы и пользуюсь своим транслятором
Для разовых сравнений эти микрооптимизации практически незаметны. Можно ещё заюзать CMOV после MOV. Вообще на больших объёмах данных гораздо быстрее заюзать SIMD где можно сразу несколько таких операций сделать - вот тут как раз и будет преимущество в скорости + можно это сделать 1 инструкцией PCMPEQD.
Я это называю PreAsm (преассемблер или предассемблер), но никак не возьмусь написать, но это скорее: МойКодXC166>PreAsmCrossForFasm>Fasm> XC166(.bin). Повозился с FasmG - не понравилось. Параллельность - да. 1. MоvXXX ...; 0 в регистры придется загрузить 2 PCMPEQD ^^^^^^^^^,память ; "элемент заполняется единицами" 3 And ...; 0...01, в регистрах-то все 1111 4 MovXXX....; из регистров в память. Итого ??
если кому интересно даю ссылку для примера на один мой проект под названием - Меню с подсказками и шевронами этот проект я делал кажется пять лет назад когда наткнулся в интернете на статью - Создание строки меню в стиле Internet Explorer если в поиске набрать эти строки скорее всего найдёте её файл заархивирован паролем - 123 он лежит у меня на облачном хранилище https://cloud.mail.ru/public/bULg/PVu3LQLiA если запустить исполняемый файл то откроется окно с кнопками меню и кнопками контрола - ребара верхнии кнопки меню это тоже по сути - ребар если поводить курсором по строкам меню можно увидеть как они окрашиваються в стиле - Internet Explorer если нажать на меню - Вид и в ниспадающем меню нажать на - Простое меню то кнопки меню приобретут обычный стиль если снять эту галку то меню станет прежним если в том же меню - Вид нажать на - Открепить меню у каждого ребара в левой стороне специально откроются вертикальные точки и если захватить эти точки мышкой можно перетащить ребар в другое место если в ребаре с кнопкой с чёрным квадратом открыть его меню то вабрав цвет можно перекрасить эту кнопку остальные кнопки просто подключены к звуковым сигналам если потащить окно мышкой за левый край окна и сделать окно меньше по ширине то дойдя до меню будут показыватся шевроны предназначение которых я думаю интуитивно понятно по сути проект заточен только для показа ребаров с меню с кнопками и шевронами делал я этот проект исключительно ради интереса если открыть файл картинку - tst.bmp то там можно увидеть какие исполняемые файлы участвуют в сборке проекта ну и время потраченное ими а в конце показано общее время сборки если посмотреть файлы проекта то можно увидеть что стиль синтаксиса в определённых случаях отличается от стиля платформы - masm32 для этого и создавался транслятор который бы переписывал кодинг проекта под чистый синтаксис - masm32 папка с решёткой - # это рабочая папка проекта и если её открыть то можно увидеть в ней файл - $.asm в этом файле и будет находится переписанный синтаксис проекта который и обрабатывает следующим этапом основной компилятор - Ml.exe и соответственно в этом файле можно посмотреть во что трансфрмировался непривычный основной синтаксис проекта но в любом случае это конечно только для любопытных а эту тему я создал для того чтобы научить свой транслятор еще одной по сути команде - logic если кому интересно по тематике транслятора можно писать на почту - assch@list.ru
Ну PCMPEQD сделает это: Если в mm/xmm слоте 0 при сравнении с 0 там будут единицы, иначе нули. Только таких операций будет выполнено сразу несколько одновременно.