Хотя я не уверен на 100% в причине, вот мое предположение.
Когда компиляция на x86 и SSE2 не включена, компилятор должен использовать стек FP x87 для всех регистров с плавающей запятой.В MSVC в режиме FP по умолчанию установлено округление с точностью до 53 бит.(Я думаю. Я не уверен на 100% в этом.)
Поэтому все операции, выполняемые в стеке FP, выполняются с двойной точностью.
Однако, когда что-то сбрасываетсядо float
точность должна быть округлена до одинарной точности.Единственный способ сделать это - сохранить его в памяти с помощью инструкции fstp
над 4-байтовым операндом памяти - и перезагрузить его.
Давайте рассмотрим пример на C4738Страница предупреждения , на которую вы ссылались:
float func(float f)
{
return f;
}
int main()
{
extern float f, f1, f2;
double d = 0.0;
f1 = func(d);
f2 = (float) d;
f = f1 + f2; // C4738
printf_s("%f\n", f);
}
Когда вы звоните func()
, d
, вероятно, сохраняется в регистре x87.Однако вызов func()
требует, чтобы точность была снижена до одинарной точности.Это приведет к округлению d
/ сохранению в памяти.Затем перезагружается и повторно повышается до двойной точности в строке f = f1 + f2;
.
Однако, если вы используете double
весь путь, компилятор может хранить d
в регистре - таким образом, обходя издержкииду в и из памяти.
Что касается того, почему это может заставить вас исчерпать регистры ... Я понятия не имею.Возможно, что семантика программы может привести к тому, что значения как двойной, так и одинарной точности будут иметь одинаковое значение, что в этом случае требует дополнительного регистра.