Нужно ли сохранять состояние FPU здесь?
Я написал простую совместную многопоточную библиотеку. В настоящее время я всегда сохраняю и восстанавливаю состояние fpu с помощью fxsave
/ fxrstor
при переключении в новый контекст. Но необходимо ли это в соглашении о вызовах cdecl?
В качестве простого примера:
float thread_using_fpu(float x)
{
float y = x / 2; // do some fpu operation
yield(); // context switch, possibly altering fpu state.
y = y / 2; // another fpu operation
return y;
}
Может ли компилятор сделать какие-либо предположения о состоянии FPU после вызова yield()
?
2 ответа
Согласно БИНАРНОМУ ИНТЕРФЕЙСУ ПРИЛОЖЕНИЯ SYSTEM V Приложение к архитектуре Intel386TM, стр. 3-12:
% st (0): если функция не возвращает значение с плавающей запятой, этот регистр должен быть пустым. Этот регистр должен быть пустым до входа в функцию.
От%st(1) до%st(7): чистые регистры с плавающей точкой не имеют определенной роли в стандартной вызывающей последовательности. Эти регистры должны быть пустыми до входа и после выхода из функции.
Таким образом, вам не нужно переключать их контекст.
Другая, более новая версия говорит это:
Процессор должен находиться в режиме x87 при входе в функцию. Поэтому каждая функция, которая использует регистры MMX, должна выдавать инструкцию emms или femms после использования регистров MMX перед возвратом или вызовом другой функции. [...] Управляющие биты регистра MXCSR сохраняются вызываемым абонентом (сохраняется при вызовах), а биты состояния сохраняются вызывающим абонентом (не сохраняются). Регистр слова состояния x87 сохраняется вызывающим абонентом, а слово управления x87 сохраняется вызываемым абонентом. [...] Все регистры x87 сохраняются вызывающими, поэтому вызывающие абоненты, использующие регистры MMX, могут использовать инструкцию более быстрого femms.
Таким образом, вам может понадобиться сохранить контрольное слово.
Нет. Вы не должны делать никаких сбережений государства. Если один поток находится в середине вычисления с плавающей запятой, где, например, установлен денормализованный флаг, и этот поток прерывается, то при возобновлении O/S или ядро установит флаги, точно так же, как восстановит другие регистры. Точно так же вам не нужно беспокоиться об этом в yield().
Изменить: Если вы делаете свое собственное переключение контекста, возможно, вам нужно будет сохранить контрольные флаги точности и округления, если вам нужно установить для них значения не по умолчанию. В противном случае снова ты в порядке.