сравнение 4 byte float

Тема в разделе "WASM.ZEN", создана пользователем cresta, 12 мар 2005.

  1. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Взял кусок из функции FpuComp, для сравнения двух 4-байтных float


    Код (Text):
    1. singleFunc proc single1:DWORD,single2:DWORD
    2.     LOCAL prevstate[108]    :BYTE
    3.  
    4.     fxam                  
    5.     fstsw ax              
    6.     fwait
    7.     sahf                          
    8.     fsave prevstate
    9.     lea   eax,single1
    10.     fild  dword ptr [eax]
    11.     lea   eax,single2
    12.     fild  dword ptr [eax]
    13.     fxch
    14.     fcom
    15.     fstsw ax
    16.     fwait
    17.     shr   al,1              
    18.     sahf                    
    19.     ja    @G
    20.     jc    @E
    21.     PrintText "="           ;single1 = single2
    22.     jmp   @EndCmp
    23. @E:
    24.     PrintText "<"           ;single1 < single2
    25.     jmp   @EndCmp
    26. @G:
    27.     PrintText ]"        ;single1 > single2
    28. @EndCmp:
    29.     frstor prevstate




    сравниваю

    -1.5 и -1.1 получается -1.5 > -1.1. Это я ошибся в коде, или действительно -1.5 > -1.1 ?

    Пробовал непосредственно

    mov eax,single1

    mov ecx,single2

    invoke FpuComp,eax,ecx,SRC1_DIMM or SRC2_DIMM

    результат тот же :dntknw:



    И ещё одна пара чисел: -1.5 Е01 < -1.1 E02 (-15 < -110)???
     
  2. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta

    Почитай внимательно описание команд FCOMxx. Сравнение происходит между регистром st(0) и источником. Если источник не указан, то подразумевается, что сравнивается st(0) и st(1). Итого либо надо операнды в сопроцессор помещать, начиная со второго, либо интерпретировать результаты сравнения наоборот.



    Если не затуманивать код сохранением состояния сопроцессора, то он должен выглядеть так:
    Код (Text):
    1. align 4
    2. fcompare proc f1 : dword, f2 : dword
    3.  
    4. option prologue : none
    5. option epilogue : none
    6.  
    7.   fld dword ptr [esp+4]  ;; f1
    8.   fld dword ptr [esp+8]  ;; f2
    9.   fcompp
    10.   fnstsw ax
    11.   sahf
    12.   ja f2_great_f1
    13.   je f2_equal_f1
    14.  
    15. f1_great_f2:
    16.   mov eax,1
    17.   ret 8
    18.  
    19. f2_equal_f1:
    20.   xor eax,eax
    21.   ret 8
    22.  
    23. f2_great_f1:
    24.   or eax,-1
    25.   ret 8
    26.  
    27. option prologue : prologuedef
    28. option epilogue : epiloguedef
    29.  
    30. fcompare endp
    31. align 4




    PS Почему для загрузки чисел с плавающей точкой ты используешь команду fild?
     
  3. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    q_q





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

    fld tbyte ptr [eax]. - с запятой :)



    Если загружать fld qword ptr [eax], то правильно ли загрузится число размером в 8 байт (double)?

    Если да, то логично было бы добавить в FpuComp возможность работы с qword'ами наравне с 4 и 10 байтными числами.



    option prologue : none

    option epilogue : none

    Эти инструкции предотвращают вставку конструкций типа

    push ebp

    mov ebp,esp

    add esp,xxx

    это так?
     
  4. Avalonec

    Avalonec New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    111
    Адрес:
    Тула
    Поищи в исходниках модуль FPU_WORK избавит от большинства трудностей.
     
  5. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta

    В справочнике по опкодам ни слова нет про команды, начинающиеся с f...

    Не те справочники используешь.

    Например, masm32\help\fpuhelp.hlp или Зубков - "2.4.6 Команды сравнения FPU" в имеющемся у меня издании 90-ая страница.



    Imho давно пора качнуть "IA-32 Intel (R) Architecture Software Developer's Manual" в трех томах. Конкретно во втором томе "3.2 Instruction reference" страница 252 "FCOM/FCOMP/FCOMPP - Compare Floating Point Values". В аттаче скриншот.



    Всё что есть мало-мальски комментированное - это исходник FpuComp

    Почитай к нему справку.
    Код (Text):
    1. SRC1_FPU        Src1 is already on the FPU
    2. SRC1_REAL   Src1 is a pointer to an 80-bit REAL number
    3. SRC1_DMEM   Src1 is a pointer to a 32-bit signed integer
    4. SRC1_DIMM   Src1 is a 32-bit signed integer
    5. SRC1_CONST  Src1 is one of the special FPU constants
    6.  
    7. SRC2_FPU    Src2 is already on the FPU
    8. SRC2_REAL   Src2 is a pointer to an 80-bit REAL number
    9. SRC2_DMEM   Src2 is a pointer to a 32-bit signed integer
    10. SRC2_DIMM   Src2 is a 32-bit signed integer
    11. SRC2_CONST  Src2 is one of the special FPU constants
    Где тут сравнение 4-ехбайтных с плавающей точкой.



    Если загружать fld qword ptr [eax], то правильно ли загрузится число размером в 8 байт (double)?

    Да. Сформируй из
    Код (Text):
    1. int dc(double d1, double d2)
    2. {
    3.   if (d1 > d2) return  1;
    4.   if (d1 < d2) return -1;
    5.                return  0;
    6. }
    7.  
    8. int fc(float f1, float f2)
    9. {
    10.   if (f1 > f2) return  1;
    11.   if (f1 < f2) return -1;
    12.                return  0;
    13. }
    asm-код и посмотри какие команды поставит компилятор.



    Эти инструкции предотвращают вставку конструкций типа ... это так?

    Да. Еще сам обязан позаботиться о выталкивании из стека параметров, если этого требует соглашение о вызове подпрограммы.

    [​IMG] 985806725__FCOMxx.GIF
     
  6. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Ну говорю ж, проглядел, что integer, а не float :)



    Для восьбайтных уже нащупал, правда в стеке запутался, поэтому без option prologue : none option epilogue : none :


    Код (Text):
    1. doubleCmpFunc proc double1:QWORD,double2:QWORD
    2.     lea eax,double1
    3.     lea ecx,double2
    4.     push ecx
    5.     push eax
    6.     call fdblcompare
    7.     PrintDec eax
    8.     ret
    9. doubleCmpFunc endp
    10.  
    11. fdblcompare proc f1Addr : dword, f2Addr : dword
    12.     mov eax,f1Addr
    13.     fld qword ptr [eax]
    14.     mov eax,f2Addr
    15.     fld qword ptr [eax]
    16.     fcompp
    17.     .....




    А что сделает C-compiler, сейчас посмотрю.



    Спасибо.
     
  7. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Значит размер загружаемого и сравниваемого определяется

    D94424 или DD4424. И второй операнд можно не загружая сравнивать. fcomp dword/qword ptr[]
     
  8. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta

    размер загружаемого и сравниваемого определяется

    D94424 или DD4424


    Не совсем так.

    Размер загружаемого - да. Размер сравниваемого - нет. Afaik в сопроцессоре числа лежат в одном формате - double extended-precision floating-point format.



    второй операнд можно не загружая сравнивать

    Да.
     
  9. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    cresta, q_q



    Не забывайте очищать стэк FPU при выходе из функции.

    Использование fsave\frstor это большие тормоза. Поэтому нужно просто аккуратно следить за состоянием стека FPU: если мы загрузили два регистра fld\fild, то должны их освободить. В данном случае - это fcompp + нужно добавить fstp st(0). Иначе после нескольких вызовов функции можем получить исключение #IS - переполнение стека FPU.
     
  10. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    leo

    В данном случае - это fcompp + нужно добавить fstp st(0).

    Зачем?

    Судя по документации PP обеспечивает pop register stack twice.
     
  11. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    q_q

    Точно, прошу прощения.

    Я кстати о такой фиче или не знал или забыл, так что еще спасибо за информацию.
     
  12. LocTb

    LocTb New Member

    Публикаций:
    0
    Регистрация:
    11 окт 2004
    Сообщения:
    54
    Народ а "fcomi" и его аналоги что не в моде, вроде только P6 надо? IMHO плюс от "fcom", что при проверке диапазона можно обойтись 1 джампом.
     
  13. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257




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

    D8 /2 FCOM m32fp Compare ST(0) with m32fp.

    DC /2 FCOM m64fp Compare ST(0) with m64fp.



    отказываясь от перехода, до выполнения которого дело может и не дойти, получаем ещё один fld. Кажется для случая единичного сравнения двух чисел это не есть гут. А если условие <= >= и т.п. то переход всего один. Или не так?

    fcomi/fcomip хорош, когда надо сравнить несколько float'ов между собой. Тогда экономятся загрузки.
     
  14. LocTb

    LocTb New Member

    Публикаций:
    0
    Регистрация:
    11 окт 2004
    Сообщения:
    54
    1 джамп (условный), поясню что имел:
    Код (Text):
    1.  
    2. fld    [TestValue]
    3. fcom   [LowBound]
    4. fnstsw ax
    5. xchg   eax,edx
    6. fcomp  [HiBound]
    7. fnstsw ax
    8. xor    ah,dh
    9. jnz    .InRange
    10.  


    вроде так.
     
  15. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    cresta

    > "Но при этом есть минус..."



    Минус очень относительный, т.к. экономия одного fld м.б.важна только в случае нехватки регистров.

    Если ограничения нет, то fld[m]+fcomi+fstp получается всего на 1 байт больше (а без fstp покороче), но зато на несколько тиков быстрее (особенно на P6), чем fcomp[m]+fnstsw+sahf.

    А потому, что fnstsw - довольно тормозная штука. Цитата из pentopt.pdf by Agner Fog (раздел 18.10):

    "The FNSTSW instruction is very slow on all processors. Using FCOMI instead of the common sequence FCOM / FNSTSW AX / SAHF will save 8 clock cycles on PPro, P2 and P3, and 4 clock cycles on P4. You should therefore use FCOMI to avoid FNSTSW wherever possible, even in cases where it costs some extra code."
     
  16. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    leo



    А где можно для команд f.... найти данные о тиках?
     
  17. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    > "А где можно для команд f.... найти данные о тиках?"



    1) Официальные, но неполные данные для P4 см. в IA-32 Intel® Architecture Optimization Reference Manual (см. мануалы от Intel)



    2) Полные, но неофициальные данные по всем пентиумам см. Agner Fog "How to optimize for the Pentium® microprocessors" (pentopt.pdf)
     
  18. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    IA-32 (2 и 3 том) есть, но что-то я или проглядел или инфа в первом томе, а по ссылке на Фога сейчас схожу.



    спасибо
     
  19. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    cresta



    IA-32 Optimization - это отдельный мануал (24896611.pdf, 2.55 MB). На указанной страничке Intel он идет после 3-го тома.
     
  20. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Скачал pentopt.pdf, вроде доступно описано. Спасибо.