Оптимизация разветвлённого условия

Тема в разделе "WASM.BEGINNERS", создана пользователем Y_Mur, 27 сен 2006.

  1. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Может кто видит подводные камни или лучшее решение?
    Если нужно проверить серию сложных условий, то для уменьшения количества переходов делаю так:
    Код (Text):
    1. xor EAX, EAX ; здесь будут флаги
    2. cmp ...
    3.   setg AH
    4.   or AL, AH ; установить флаг 1
    5. cmp ...
    6.   setl AH
    7.   shl AH, 1
    8.   or AL, AH ; установить флаг 2
    9. or EBX, EBX
    10.   sets AH   ; EBX < 0
    11.   ror AH, 1
    12.   or AL, AH ; установить флаг 3
    13. cmp ... другое условие
    14.   setg AH
    15.   or AL, AH ; опять установить флаг 1
    16. ; и дальше цепочка проверок с повторной установкой флагов
    17. ; ...
    18. ; а теперь собственно переходы в уменьшенном количестве:
    19. .IF AL & 01h    ; сработал флаг 1
    20. ; ...
    21. .IF !(AL & 02) ; нет флага 2
    22. ; ...
    23. .IF AL & 80h  ; сработал флаг 3
    24. ; ...
    Перед дальнейшим использованием EAX:
    xor EAX, EAX ; для устранения частичной задержки (по Фогу)
    mov EAX, ...
    Если сложное условие собирается по ИЛИ то прямая установка флага в set.. и прямая проверка в .IF
    Если сложное условие собирается по И то инверсная установка флага в set.. и проверка на отсутствие флага в .IF
    Если сложное условие комбинирует ИЛИ и И, то проверять флаги группами, например:
    and AL, 81h ; исключить влияние флага 2
    .IF AL == 81h ;(блок_условий_1 & блок_условий_3)
    или строить цепочечную конструкцию .IF ... .ELSEIF ...
    Пробовал реализовать подобное на cmov.., но задействуется слишком много регистров и\или значений в памяти
     
  2. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    А не проще воспользоваться методиками организации конструкции switch в популярных компиляторах? (сбалансированные деревья)
     
  3. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    crypto
    А чтобы деревья балансировать нужно, что-то указывать, или компилятор сам догадается? Если не трудно кинь примерчик, и во что он транслируется на асме.
     
  4. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Y_Mur
    Комилятор сам догадывается, в зависимости от конструкции switch. Если переключение происходит по нумератору, то создается таблица косвенных переходов. Если же компилируется конструкция вроде обработчика событий в WndProc, в которой разброс значений может быть очень сильным, тогда создается дерево и конструкция строится по этому дереву.
    Примерчик наверное имеется, надо порыться...
     
  5. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    А вообще принцип такой:
    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

    и так далее.
    А про построение таких деревьев много литературы в Инете.
     
  6. nobodyzzz

    nobodyzzz New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2005
    Сообщения:
    475
    Y_Mur
    на счет примера во что компилятор преврашает switch посмотри касперски статья есть на wasm.ru
    http://wasm.ru/publist.php?list=23
     
  7. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Спасибо всем - классные статьи - интересная методика (на будущее пригодится :),
    но сейчас я решаю немного другую задачу, когда навороченное условие типа
    ((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 вариантов.
    И мне по прежнему кажется, что в этом случае изложенный выше подход окажется эффективнее кучи переходов (даже хитро сбалансированной), особенно если много разных блоков, в каждом из которых нужно проверять такое же по навороченности (но другое по логической сути) условие, и эти блоки часто и непредсказуемо чередуются и соответственно вытесняют друг друга из ВТВ.
     
  8. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Мне кажется, и в этом случае компилятор создает достаточно оптимальную конструкцию. Все равно ты используешь операции сравнения. Отличие твоей идеи в том, что ты результаты сравнений сохраняешь в регистрах, но потом ты их начинаешь опять анализировать. А в ветвлениях используются условные переходы, наверное получится даже короче.
    Попробуй твои сложные условия скомпильнуть и посмотри, что получилось.
     
  9. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Если бы это было так просто, я бы и вопросов не задавал, но у меня С++ то с виндами не дружат, то на инклюды ругаются, а закачке psdk (1,2 Гб) я так и не понял какой же раздел качать, чтобы хоть по минимуму icl с виндами подружить :dntknw:
    Так что кодирую в MASM - оно проще и привычнее :)