Что именно означает "денормальный ввод" в сборке, когда мы рассматриваем использование флага DAZ для плавающих точек SSE

Я прочитал эту статью и " /questions/45468630/vliyayut-li-nenormalnyie-flagi-kak-denormals-are-zero-daz-na-sravnenie-na-ravenstvo, и я понимаю использование и разницу между флагами FTZ и DAZ.

DAZ применяется на входе, FTZ - на выходе из операции FP.

Что меня смутило, так это откуда берется денормальное значение в виде сборки, если установлена FTZ. Я думаю, что это могут быть только постоянные значения либо как непосредственные операнды, либо из раздела.rodata (доступ с относительной адресацией RIP).

Но в своем двоичном файле я обнаружил, что в этих местах нет денормальных значений, но он по-прежнему страдает проблемами FP-ASSIST, что приводит к плохой производительности.

Если я установлю и DAZ, и FTZ, проблема исчезнет, ​​и производительность улучшится. На самом деле я даже не нахожу никаких ненормальных входов в исходном коде. Я действительно запутался, откуда берутся денормальные значения?


Другой вопрос кстати, по инструкции vmovsd 0x9498(%rip),%xmm0, предполагая 0x9498(%rip) это денормальное значение, что происходит с xmm0 если после выполнения этой инструкции установить FTZ или DAZ соответственно?

В моем понимании DAZ заставит 0x9498(%rip) как ноль и mov 0до xmm0; ЗСТ переместится0x9498(%rip) к xmm0 и обнаружил, что это ненормальное значение, поэтому промойте xmm0к нулю. Я не уверен, это правильно?

1 ответ

Денормальное или субнормальное - это значение с полем экспоненты = 0 в двоичном формате IEEE. https://en.wikipedia.org/wiki/Double-precision_floating-point_format

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

Да, большую часть времени FTZ на выходе достаточно, потому что большинство значений с плавающей запятой являются результатами других вычислений FP. И да, FTZ необходима, потому что mul/div/add/sub для нормальных чисел может привести к субнормальным результатам. (Для добавления входов нужны противоположные знаки). Другая "базовая" операция IEEE с точным округлением, sqrt, не может создавать субнормальные значения, поскольку она приближает числа к 1.0.

Очевидным было бы использовать perf recordчтобы узнать, где вы получаете FP-ассисты, и добавить туда дополнительные чеки для печати или что-то еще, когда вы найдете там ненормальное. (Затем установите точку останова в этой ветке, чтобы вы могли изучить ситуацию.)


Возможные источники денормальных значений (не исчерпывающие) с установленной ЗСТ, т. Е. Кроме математических операций FP:

  • String-to-float, который строит битовый шаблон FP с целым числом повышенной точности, как в Glibcstrtod
  • Входные файлы / сеть, если вы читаете двоичные данные.
  • Другие потоки или через разделяемую память от других процессов, работающих без FTZ. (FTZ/DAZ и режим округления в MXCSR - это архитектурное состояние для каждого потока. Кстати, если вы установите FTZ только в основном потоке после запуска другого потока, это не будет эффективно для уже запущенного потока.)
  • Возможно целочисленное манипулирование битовыми шаблонами FP, например nextafter. Также возможно как часть внутренней частиexp реализация, которая вставляет целое число в поле экспоненты double.
  • Значения констант времени компиляции. Однако они не должны появляться в исходном коде как буквальные значения. напримерstatic double foo = DBL_MIN / 4.0;будет денормальным во время компиляции. Но вы найдете их в.rodata или .data. Неконстантные ненулевые статические / глобальные переменные входят в.data.

Очевидно, что любые ручные манипуляции с битовыми шаблонами FP с использованием целых чисел тоже могут это сделать. Как использовать биты в байте для установки двойных слов в регистре ymm без AVX2? (Инверсия vmovmskps) могла бы произвести денормальные входные данные для сравнения, если бы я не потратил дополнительную инструкцию, чтобы избежать этого, но это необычный трюк с ручной векторизацией, который компиляторы не будут делать за вас.

непосредственные операнды

x86 не имеет непосредственного FP; тебе бы пришлосьmov rax, imm64 / movq xmm0, raxили похожие. Но компиляторы этого не делают, потому что обычно более эффективно загружать из.rodata.

для обучения vmovsd 0x9498(%rip),%xmm0

vmovsdэто просто загрузка и всегда точно копирует 64 бита; архитектурно эквивалентенvmovq SIMD-целочисленная нагрузка.

Он не передает значение через ALU, поэтому биты MXCSR не влияют на vmovsd, Перемешивание FP и т. Д. Затрагиваются только инструкции, которые выполняют фактические вычисления FP и могут вызывать исключения FP. Вы можете сказать это, посмотрев на раздел исключений ручной записи asm. например roundsd подчиняется DAZ для возможного округления ввода до нуля, прежде чем округлять его в соответствии с указанным режимом.

Другие вопросы по тегам