Инструкция FLD x64 бит

У меня есть небольшая проблема с инструкцией FLD в x64 бит ... хочу загрузить значение Double в указатель стека FPU в регистре st0, но это кажется невозможным. В Delphi x32 я могу использовать этот код:

function DoSomething(X:Double):Double;
asm

  FLD    X
   // Do Something ..
  FST Result

end;

К сожалению, в x64 тот же код не работает.


person SMP3    schedule 03.04.2013    source источник
comment
Определить не получается. Это крах? Не компилируется? Не возвращает ли он ожидаемый результат?   -  person Michael    schedule 03.04.2013
comment
Вы читали о совместимости с Win64 в справке Delphi? Говорят, что в Win64 нет 10-байтного типа Extended. И это показывает, что Delphi Win64 не использует FPU (x86). Вместо этого он использует SSE. Таким образом, использование инструкций FPU проблематично. Также будьте осторожны при использовании BAsm x64 - есть ошибки, которые уничтожают данные или даже инвертируют поток управления программой.   -  person Arioch 'The    schedule 03.04.2013
comment
в x86_64 FPU не следует использовать, если вам не нужна повышенная точность. SSE быстрее и стабильнее в своих результатах   -  person phuclv    schedule 04.09.2018


Ответы (3)


В режиме x64 параметры с плавающей запятой передаются в xmm-регистрах. Поэтому, когда Delphi пытается скомпилировать FLD X, он становится FLD xmm0, но такой инструкции нет. Сначала вам нужно переместить его в память.

То же самое и с результатом, его нужно передать обратно в xmm0.

Попробуйте это (не проверено):

function DoSomething(X:Double):Double;
var
  Temp : double;
asm
  MOVQ qword ptr Temp,X
  FLD Temp
  //do something
  FST Temp
  MOVQ xmm0,qword ptr Temp
end;
person Ville Krumlinde    schedule 03.04.2013
comment
›Поэтому, когда Delphi пытается скомпилировать FLD X, он становится FLD XMM0... ЧТО О РЕЗУЛЬТАТЕ FLD !!! почему компилятор принимает загрузку Result .. это ошибка !! - person SMP3; 03.04.2013
comment
@ SMP3 SMP3: оказывается, когда вы выполняете результат FST, BASM выделяет временное хранилище в стеке для результата, а затем добавляет в конце дополнительную инструкцию для загрузки xmm0 с этим значением. Я не знал этого. Посмотрите сами в режиме дизассемблирования в отладчике. - person Ville Krumlinde; 03.04.2013
comment
Это ошибка? Нет. На x64 используйте SSE, а не x87. Но вы должны перестать заниматься asm и позволить компилятору сделать всю работу. - person David Heffernan; 03.04.2013

Delphi наследует Microsoft x64 Соглашение о вызовах. Таким образом, если аргументы функции/процедуры имеют тип float/double, они передаются в регистрах XMM0L, XMM1L, XMM2L и XMM3L.

Но вы можете использовать var перед параметром в качестве обходного пути, например:

function DoSomething(var X:Double):Double;
asm
  FLD  qword ptr [X]
  // Do Something ..
  FST Result
end;
person GJ.    schedule 03.04.2013
comment
Хороший обходной путь. Ограничение заключается в том, что вы не можете передавать константные литералы, такие как DoSomething(1.0) или переменные, объявленные как Single. - person Ville Krumlinde; 03.04.2013
comment
@Ville Krumlinde: Действительно, если вам нужно вызвать функцию с постоянным параметром, то в разделе const сначала объявите константу. :) - person GJ.; 03.04.2013

Вам не нужно использовать устаревшие регистры стека x87 в коде x86-64, поскольку SSE2 является базовой линией, обязательной частью x86-64 ISA. Вы можете и должны выполнять скалярные вычисления FP, используя addsd, mulsd, sqrtsd и т. д. on, на регистрах XMM. (Или addss для поплавка)

Соглашение о вызовах Windows x64 передает аргументы float/double FP в XMM0..3, если они являются одним из первых четырех аргументов функции. (т.е. 3-й общий аргумент идет в xmm2, если это FP, а не 3-й аргумент FP идет в xmm2.) Он возвращает значения FP в XMM0.

Используйте x87 только в том случае, если вам действительно нужна 80-битная точность внутри вашей функции. (Такие инструкции, как fsin и fyl2x, небыстры и обычно могут быть выполнены обычными математическими библиотеками с использованием инструкций SSE/SSE2.

function times2(X:Double):Double;
asm
    addsd  xmm0, xmm0       // upper 8 bytes of XMM0 are ignored
    ret
end

Сохранение в памяти и перезагрузка в регистр x87 стоит вам около 10 циклов задержки без какой-либо выгоды. Скалярные инструкции SSE/SSE2 так же быстры или даже быстрее, чем их эквиваленты x87, и их легче программировать и оптимизировать, поскольку вам никогда не понадобится fxch; это плоский дизайн регистра, а не стек. (https://agner.org/optimize/). Кроме того, у вас есть 15 регистров XMM.


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

person Peter Cordes    schedule 04.09.2018