Стек x87 FP все еще актуален?

Я заметил, что компиляторы генерируют код, нацеленный на регистры SIMD, каждый раз, когда используется double арифметика. Это относится как к неоптимизированному, так и к оптимизированному коду. Означает ли это, что модуль x87 FP можно считать устаревшим и использовать только для обеспечения обратной совместимости?

Я также заметил, что другие «популярные» платформы также полагаются на свои соответствующие реализации SIMD, а не на FP, спроектированный как стек.

Кроме того, реализация SIMD, как правило, имеет ширину не менее 128 бит, поэтому мне интересно, означает ли это, что (внутренняя) точность операций выше, чем для модуля x87 FP?

Я также задаюсь вопросом о производительности, пропускной способности и задержке, учитывая, что SIMD был задуман с учетом векторного выполнения, поэтому мне интересно, как они справляются со скалярами.


person Community    schedule 09.10.2014    source источник
comment
На самом деле FPU может быть более точным, потому что SIMD хранит несколько значений в этих битах, в настоящее время он поддерживает 64-битные удвоения и 32-битные числа с плавающей запятой. Существуют также скалярные инструкции SSE. Однако у FPU есть некоторые функции, которых нет у SSE.   -  person Jester    schedule 09.10.2014
comment
@Jester - вы подразумеваете, что модули SIMD не используют полные 128 бит для хранения одного значения? И что вместо этого он обрабатывается как упакованный double и имеет только 64 бита?   -  person    schedule 09.10.2014
comment
Он прочно занесен в список кодовых видов, находящихся под угрозой исчезновения. Все внесли критические изменения в свои 64-битные генераторы кода. Большая тройка поменялась местами. Есть несколько отстающих, например, 32-битный джиттер .NET. Давно пора назвать катастрофу 80-битного FPU далеким плохим воспоминанием.   -  person Hans Passant    schedule 09.10.2014
comment
@HansPassant Можно было бы выдвинуть противоположный аргумент, то есть, поскольку исторический FPU был освобожден при переключении на регистры SSE2, теперь он снова доступен для использования по своей первоначальной цели - обеспечению повышенной точности. Больше нет причин делать вид, что уменьшенная значащая ширина должна быть нормальным состоянием исторической FPU.   -  person Pascal Cuoq    schedule 09.10.2014
comment
@PascalCuoq - было бы лучше вложить эту логику холостого хода в добавление поддержки 128-битных скаляров в модулях SIMD. Но это потребовало бы отказа от устаревших вещей и мучительной обратной совместимости. Думаю, для хранения данных будет достаточно даже 64 бит, но для промежуточных этапов вычислений 128 — это просто › 80.   -  person    schedule 09.10.2014
comment
@HansPassant: 80-битный FPU... катастрофа? Что именно в нем было катастрофическим?   -  person tmyklebu    schedule 09.10.2014
comment
@tmyklebu Ну, мы трое знаем, что x87 является основной причиной, по которой долгое время было трудно реализовать язык программирования, который предлагал простую арифметику с плавающей запятой с двойной точностью. Воспроизводимость результатов со всеми компиляторами и уровнями оптимизации часто важнее точности, а вычисления с плавающей запятой приобрели репутацию ненадежного, что досаждает ему и по сей день.   -  person Pascal Cuoq    schedule 09.10.2014
comment
@tmyklebu Java, как было определено в середине 90-х, было трудно реализовать для инструкций x87, и только в C99 (насколько мне известно) определение языка, которое было детерминированным и простым в реализации с помощью инструкции 387, было предложил. Это предложение было реализовано в GCC в 2008 году, и опять же, насколько мне известно, GCC был первым компилятором C, который его реализовал (и, возможно, до сих пор является единственным, кто его реализовал).   -  person Pascal Cuoq    schedule 09.10.2014
comment
@PascalCuoq: Выполнение double математики с x87 всегда вызывало проблемы. Java не удалось включить тип long double. Однако ни в одной из этих катастроф нельзя винить дизайн x87; использование long double математики в программах на C было достаточно простым (хотя и не полностью переносимым), а Java не существовало до тех пор, пока не появился 387. Я согласен, что стигма, все еще связанная с математикой с плавающей запятой, невелика.   -  person tmyklebu    schedule 09.10.2014
comment
@PascalCuoq: Что в этом должно быть сложного? Включите тип long double и укажите, что все промежуточные вычисления будут выполняться как long double, и любая утечка регистра требуется для сохранения длинных двойных значений. Я думаю, это то, что Turbo Pascal делал в 1980-х годах, и это работало очень хорошо. Даже если long double места хранения обычно должны быть дополнены до 12 или 16 байтов (язык/фреймворк может предлагать структуры, которые, например, объединяют одно или три значения типа long double со значением типа uint16 для общего размера 12 или 32 байтов) .   -  person supercat    schedule 14.10.2014
comment
@supercat, тебе следует писать компиляторы. Вы бы справились с этим лучше, чем лучшие специалисты Microsoft (включая тех, кто работал над компилятором C и тех, кто определял .NET). Я даже не буду упоминать Clang, который спонсируется Apple и Google, чтобы не обидеть людей.   -  person Pascal Cuoq    schedule 14.10.2014
comment
@PascalCuoq: я ожидаю, что люди не хотят писать спецификацию языка, которая будет определять семантику, для которой x87 будет единственной эффективной реализацией. Трагедия, ИМХО, поскольку есть много ситуаций, когда возможность использовать тип более высокой точности для промежуточных результатов может значительно упростить многие виды вычислений. Часто намного гарантировать, что вычисление дает результат в пределах нескольких младших разрядов от правильности, чем гарантировать, что оно дает результат, который находится в пределах 9/16 младших разрядов от правильности; действительно, в некоторых случаях уточнение этого последнего LSB может занять больше времени...   -  person supercat    schedule 14.10.2014
comment
... чем все остальные этапы вычислений вместе взятые.   -  person supercat    schedule 14.10.2014
comment
@PascalCuoq: В любом случае, я почти уверен, что Turbo Pascal 5.0, который U использовал в 1988 году, реализовал семантику, эквивалентную сегодняшнему FLT_EVAL_METHOD==2; тот факт, что так много компиляторов между тем и сейчас выбрали семантику «мне все равно», которую вы в другом месте признали отвратительной, не означает, что эффективная и семантически разумная реализация должна быть сложной.   -  person supercat    schedule 14.10.2014
comment
@PascalCuoq: когда я впервые прочитал ваш комментарий, я подумал, что вы саркастичны; видя, что вы написали в другом месте, возможно, нет. Вы хоть представляете, почему компиляторы перешли от последовательного выполнения промежуточных вычислений в виде 80-битных значений к бессистемному сочетанию точности? Выполнение всех вычислений с максимально возможной точностью кажется проще, чем попытка выполнить float операций с точностью float и double операций с точностью double, и в большинстве случаев это будет так же быстро или даже быстрее, чем попытки выполнить операции с несколькими уровнями точности.   -  person supercat    schedule 14.10.2014
comment
@PascalCuoq: хотя оценка d1=d2+d3; с использованием только double может быть немного более точной, чем использование расширенной точности и округления, использование расширенной точности для d1=d2+d3+d4; часто намного точнее, чем использование double без суммирования Кахана или других подобных алгоритмов, а на x87 будет быть намного быстрее, чем использование суммирования Каана для получения точных результатов, используя только double.   -  person supercat    schedule 14.10.2014
comment
@supercat Я был саркастичен, сарказм был направлен на разработчиков последних платформ компиляции. Однако я должен отметить, что наличие недокументированной дисциплины для промежуточных вычислений повышенной точности дает лишь некоторые преимущества. Для получения максимальной выгоды правила должны быть задокументированы. Была ли задокументирована работа Turbo Pascal с FP? И нет, «единственного очевидного выбора» не существует. Даже C11 нужно было прояснить что-то, оставшееся двусмысленным в C99 (return fpexpr;)   -  person Pascal Cuoq    schedule 14.10.2014
comment
@PascalCuoq: у меня нет руководств под рукой, поэтому я не знаю точно, что они указали в отношении поведения. Важно то, что компиляторы никогда не пропускали регистры с плавающей запятой с более низкой точностью. Я недоумеваю, почему при использовании FPU, где время, необходимое для операции, не зависит от точности, компилятор не будет ни детерминистически округлять промежуточные значения с низкой точностью до более низкой точности, ни последовательно поддерживать их с полной точностью, а вместо этого попытается промежуточные продукты разлива только с требуемой точностью. Для меня это лишняя работа ради худших результатов.   -  person supercat    schedule 15.10.2014
comment
@PascalCuoq: Если бы я разрабатывал среду JIT, у меня был бы только один набор операций с плавающей запятой и типы с плавающей запятой для одинарного, двойного и лучшего, где лучше всего может быть 64, 80 или 128 бит. в зависимости от реализации, но сумма, произведение и т. д. любых значений с плавающей запятой всегда будут оцениваться как лучший тип, каким бы он ни был.   -  person supercat    schedule 15.10.2014


Ответы (1)


Кроме того, реализация SIMD, как правило, имеет ширину не менее 128 бит, поэтому мне интересно, означает ли это, что (внутренняя) точность операций выше, чем для модуля x87 FP?

Ширина SIMD-регистра не равна ширине одного отдельного компонента вектора, который он представляет. Широко доступные наборы инструкций SIMD предлагают максимум формат IEEE 754 binary64 (ширина 64 бита). Это далеко не так хорошо, как исторический 80-битный расширенный формат для точности или диапазона.

Многие компиляторы C делают 80-битный формат доступным как тип long double. Я использую его часто. Его хорошо использовать для большинства промежуточных вычислений: его использование помогает сделать конечный результат более точным, даже если конечный результат предназначен для возврата в виде двоичного64 double. Одним из примеров является функция в этом вопросе, для которого имеет место математически интуитивное свойство конечного результата, если промежуточные вычисления выполняются с long double, но не в том случае, если промежуточные вычисления выполняются с тем же типом double, что и входные и выходные данные.

Точно так же среди многих ограничений, которые необходимо было сбалансировать при выборе параметров для расширенного 80-битного формата, одним из соображений является то, что он идеально подходит для вычислить двоичную64-функцию pow(), составив 80-битные expl() и logl(). Дополнительная точность необходима для получения хорошей точности конечного результата.

Однако я должен отметить, что, когда «промежуточные» вычисления представляют собой одну базовую операцию, лучше не использовать расширенную точность. Другими словами, когда x и y относятся к типу double, точность (double)(x * (long double)y) немного хуже, чем точность x * y. Два выражения почти всегда дают одинаковые результаты, а в тех редких случаях, когда они различаются, x * y немного точнее. Это явление называется двойным округлением.

person Pascal Cuoq    schedule 09.10.2014
comment
Значит, нет 128-битного представления с плавающей запятой для использования в модулях SIMD? - person ; 09.10.2014
comment
например IEEE 754 двоичный формат с плавающей запятой четверной точности - person ; 09.10.2014
comment
@ user3735658 В большинстве 128-битных наборов инструкций SIMD «128-битный регистр» представляет два binary64 или четыре binary32 и никогда не может использоваться для одного единственного значения binary128. - person Pascal Cuoq; 09.10.2014
comment
Я предполагаю, потому что оборудование не поддерживает такие операции? Хотя 128-битная плавающая точка была бы хороша... - person ; 09.10.2014
comment
@user3735658 user3735658 Было бы (и я часто использую extended double как доступное второе лучшее решение). GCC также предлагает программную эмуляцию для четырехкратной точности, доступную как __float128. - person Pascal Cuoq; 09.10.2014
comment
@ user3735658: Вы, безусловно, можете поместить значение четырехкратной точности в регистр SIMD, но ни один из MMX, SSE ... SSE4.2 не предоставляет никаких инструкций для выполнения математических операций с таким типом. Все, что вы можете сделать, это загрузить и сохранить. - person Ben Voigt; 09.10.2014
comment
Несмотря на то, что двойное округление может немного снизить точность, все же есть ситуации, когда оно может быть семантически полезным. Например, может быть полезно иметь обещание системы типов, что если t неявно преобразуется в U, а (U)t в V, то (V)t будет эквивалентно (V)(U)t. Можно поддерживать такую ​​гарантию, разрешая неявное приведение типов из целых чисел к высокоточным типам с плавающей запятой или из высокоточных типов с плавающей запятой к типам с высокой точностью, но только если определены приведения из целых чисел непосредственно к типам с более низкой точностью. быть двукратным. - person supercat; 14.10.2014