Почему встроенная функция FMA _mm256_fmadd_pd() имеет 3 мнемоники asm: "vfmadd132pd", "231" и "213"?
Может ли кто-нибудь объяснить мне, почему существуют 3 варианта команды плавного умножения-накопления: vfmadd132pd
, vfmadd231pd
и vfmadd213pd
, в то время как существует только один C intrinsics _mm256_fmadd_pd
?
Чтобы сделать вещи простыми, в чем разница (в синтаксисе AT & T)
vfmadd132pd %ymm0, %ymm1, %ymm2
vfmadd231pd %ymm0, %ymm1, %ymm2
vfmadd213pd %ymm0, %ymm1, %ymm2
Я понятия не имел из руководства по интуиции Intel. Я спрашиваю, потому что я вижу их все на выходе ассемблера куска кода C, который я написал. Спасибо.
Чистый ответ (повторное формирование ответов ниже)
Для варианта ijk
значение vfmaddijkpd
:
- Синтаксис Intel:
op(i) * op(j) + op(k) -> op(1)
- Синтаксис AT & T:
op(4-i) * op(4-j) + op(4-k) -> op(3)
где op(n)
обозначает n-й операнд после команды. Таким образом существует преобразование reverse между двумя:
n <- 4 - n
Ответы
Ответ 1
Слитые инструкции умножения-сложения умножают два (упакованные) значения, добавляют третье значение и затем перезаписывают одно из значений результатом. Только одно из трех значений может быть операндом памяти, а не регистром.
Это работает так, что все три инструкции перезаписывают ymm0
и позволяют только ymm2
быть операндом памяти. Выбор инструкции определяет, какие два операнда умножаются, а какие добавляются.
Предполагая, что ymm0 является первым операндом в синтаксисе Intel (или последним в синтаксисе AT & T):
vfmadd132pd: ymm0 = ymm0 * ymm2/mem + ymm1
vfmadd231pd: ymm0 = ymm1 * ymm2/mem + ymm0
vfmadd213pd: ymm0 = ymm1 * ymm0 + ymm2/mem
При использовании встроенных функций C этот выбор не требуется: встроенная функция не перезаписывает значение, а возвращает его результат, а также позволяет всем трем значениям считываться из памяти. Компилятор добавит чтение/запись памяти, если необходимо, и выделит временный регистр для хранения результата, если он не хочет, чтобы какое-либо из трех значений было перезаписано. Он выберет одну из трех инструкций по своему усмотрению.
Ответ 2
Это находится в инструкции по сборке, а также в его HTML-фрагментах, например в записи для VFMADD * PD:
VFMADD132PD: Умножение двух или четырех упакованных с двойной точностью значения с плавающей точкой от первого исходного операнда до двух или четыре упакованных значения с плавающей точкой двойной точности в третьем источнике операнд, добавляет промежуточный результат бесконечной точности к двум или четыре упакованных значения с плавающей запятой двойной точности в втором исходный операнд, выполняет округление и сохраняет полученные два или четыре упакованные значения с плавающей запятой двойной точности к месту назначения операнд (первый исходный операнд).
VFMADD213PD: Умножает два или четыре упакованных значения с плавающей запятой двойной точности из второго исходный операнд с двумя или четырьмя упакованными с двойной точностью Значения с плавающей точкой в первом исходном операнде добавляют бесконечность Точность промежуточного результата до двух или четырех упакованных значения с плавающей запятой двойной точности в третьем операнде источника, выполняет округление и сохраняет полученные два или четыре упакованных значения с плавающей запятой двойной точности для целевого операнда (первый операнд источника).
VFMADD231PD: Умножает два или четыре упакованных значения с плавающей запятой двойной точности из второго источника в два или четыре упакованных значения с плавающей точкой двойной точности в третьем операнд источника, добавляет промежуточный результат с бесконечной точностью к два или четыре упакованных значения с плавающей точкой двойной точности в первый исходный операнд, выполняет округление и сохраняет полученные два или четыре упакованных значения с плавающей точкой двойной точности к desti- операнд нации (операнд первого источника).