Может кто видит подводные камни или лучшее решение? Если нужно проверить серию сложных условий, то для уменьшения количества переходов делаю так: Код (Text): xor EAX, EAX ; здесь будут флаги cmp ... setg AH or AL, AH ; установить флаг 1 cmp ... setl AH shl AH, 1 or AL, AH ; установить флаг 2 or EBX, EBX sets AH ; EBX < 0 ror AH, 1 or AL, AH ; установить флаг 3 cmp ... другое условие setg AH or AL, AH ; опять установить флаг 1 ; и дальше цепочка проверок с повторной установкой флагов ; ... ; а теперь собственно переходы в уменьшенном количестве: .IF AL & 01h ; сработал флаг 1 ; ... .IF !(AL & 02) ; нет флага 2 ; ... .IF AL & 80h ; сработал флаг 3 ; ... Перед дальнейшим использованием EAX: xor EAX, EAX ; для устранения частичной задержки (по Фогу) mov EAX, ... Если сложное условие собирается по ИЛИ то прямая установка флага в set.. и прямая проверка в .IF Если сложное условие собирается по И то инверсная установка флага в set.. и проверка на отсутствие флага в .IF Если сложное условие комбинирует ИЛИ и И, то проверять флаги группами, например: and AL, 81h ; исключить влияние флага 2 .IF AL == 81h ;(блок_условий_1 & блок_условий_3) или строить цепочечную конструкцию .IF ... .ELSEIF ... Пробовал реализовать подобное на cmov.., но задействуется слишком много регистров и\или значений в памяти
А не проще воспользоваться методиками организации конструкции switch в популярных компиляторах? (сбалансированные деревья)
crypto А чтобы деревья балансировать нужно, что-то указывать, или компилятор сам догадается? Если не трудно кинь примерчик, и во что он транслируется на асме.
Y_Mur Комилятор сам догадывается, в зависимости от конструкции switch. Если переключение происходит по нумератору, то создается таблица косвенных переходов. Если же компилируется конструкция вроде обработчика событий в WndProc, в которой разброс значений может быть очень сильным, тогда создается дерево и конструкция строится по этому дереву. Примерчик наверное имеется, надо порыться...
А вообще принцип такой: sub eax, 2000 //корень дерева, из которого выходят две ветви ja @1 //скажем левая ветвь ведет в вершину 1 jb @2 //правая ветвь ведет в вершину 2 //case 2000: ... jmp exit @1: sub eax, 1000 //из вершины 1 выходят тоже две ветки ja @3 //левая - в вершину 3 jb @4 //правая - в вершину 4 //case 3000: ... jmp exit @2: dec eax //вершина 2 jnz @5: //case 3001: ... jmp exit и так далее. А про построение таких деревьев много литературы в Инете.
Y_Mur на счет примера во что компилятор преврашает switch посмотри касперски статья есть на wasm.ru http://wasm.ru/publist.php?list=23
Спасибо всем - классные статьи - интересная методика (на будущее пригодится , но сейчас я решаю немного другую задачу, когда навороченное условие типа ((A=>5) OR (B <7) OR (C>10) OR (D<25)) AND ((E=>5) OR (F <7) OR (G>10) OR (H<25)) AND (L<>7) в конечном итоге сводится к ответу ДА/НЕТ, или несколько таких многозвенных сравнений приводят к выбору из всего 2-3 вариантов. И мне по прежнему кажется, что в этом случае изложенный выше подход окажется эффективнее кучи переходов (даже хитро сбалансированной), особенно если много разных блоков, в каждом из которых нужно проверять такое же по навороченности (но другое по логической сути) условие, и эти блоки часто и непредсказуемо чередуются и соответственно вытесняют друг друга из ВТВ.
Мне кажется, и в этом случае компилятор создает достаточно оптимальную конструкцию. Все равно ты используешь операции сравнения. Отличие твоей идеи в том, что ты результаты сравнений сохраняешь в регистрах, но потом ты их начинаешь опять анализировать. А в ветвлениях используются условные переходы, наверное получится даже короче. Попробуй твои сложные условия скомпильнуть и посмотри, что получилось.
Если бы это было так просто, я бы и вопросов не задавал, но у меня С++ то с виндами не дружат, то на инклюды ругаются, а закачке psdk (1,2 Гб) я так и не понял какой же раздел качать, чтобы хоть по минимуму icl с виндами подружить Так что кодирую в MASM - оно проще и привычнее