MMX для тех, кто о нем ничего не знает 1. Введение Технология MMX расширяет функциональные возможности процессоров архитектуры Intel при полной совместимости с программами для прошлых поколений процессоров. Все программное обеспечение, созданное для ранее выпущенных процессоров, без всяких изменений может выполняться на процессорах с технологией MMX. MMX-команды "общаются" с операционной системой точно так же, как и команды с плавающей запятой. Механизм сохранения и восстановления состояния вычислений с плавающей запятой применим и для сохранения (восстановления) состояния программы, использующей технологию MMX. Фактически технология MMX не означает "нового" режима работы процессоров архитектуры Intel. 2. Общее описание В основе технологии MMX лежит расширение набора команд процессора с учетом потребностей современных мультимедиа-программ. Команды технологии MMX работают с новыми типами данных: 64-разрядными целочисленными данными, а также с данными, упакованными в группы (векторы) общей длиной 64 бита. MMX-команды используют восемь 64-разрядных регистров. К регистрам обеспечивается прямой доступ по именам: MM0,..., MM7. Никакие другие команды не могут обращаться к этим регистрам. "Физически" регистры технологии MMX размещены в мантиссах регистров с плавающей запятой (биты 0-63). Таким образом, при записи любого значения в MMX-регистр это значение попадает в один из регистров с плавающей запятой. При выполнении MMX-команд - все биты порядка и знаковый бит в соответствующем регистре с плавающей запятой заполняются единицами (это биты 64-79) - все слово состояния регистров с плавающей запятой заполняется нулями. MMX-команды исполняются в том же режиме процессора, что и команды с плавающей запятой. Поэтому при исполнении всех MMX-команд (кроме EMMS) "портится" слово состояния регистров с плавающей запятой. Команда EMMS обеспечивает переход процессора от исполнения MMX-команд к исполнению обычных команд с плавающей запятой: она устанавливает значение 1 во всех разрядах слова состояния. Заканчивайте командой EMMS любой фрагмент программы, в котором есть MMX-команды. Если этого не делать, то - операции с плавающей запятой будут давать неверные результаты; - иногда в результате операций с плавающей запятой будут генерироваться исключения типа Stack overflow. MMX-команды никогда не генерируют арифметических исключений. Ho в результате выполнения этих команд могут генерироваться прерывания арифметики с плавающей запятой, если до выполнения MMX-команды уже было сгенерировано исключение "плавающей" арифметики. MMX-команды могут генерировать исключения по доступу к памяти. MMX-команды имеют следующий синтаксис: instruction [dest,src] Здесь instruction - имя команды, dest обозначает выходной операнд, src - входной операнд. Большинство команд имеют суффикс, который определяет тип данных и используемую арифметику: - US (unsigned saturation) - арифметика с насыщением, данные без знака. - S или SS (signed saturation) - арифметика с насыщением, данные со знаком. Если в суффиксе нет ни S, ни SS, используется циклическая арифметика (wraparound). - B, W, D, Q указывают тип данных. Если в суффиксе есть две из этих букв, первая соответствует входному операнду, а вторая - выходному. Например, MMX-команда paddusw MM4,mem1 выполняет сложение слов без знака. Первые слагаемые находятся в MMX-регистре MM4, вторые - в памяти по адресу mem1. Суммы записываются в регистр MM4. MMX-команды используют новые типы данных: упакованные байты (packed byte, суффикс команды b), упакованные слова (packed word, суффикс w), упакованные двойные слова (packed doubleword, суффикс d) и 64-разрядные слова (quadword, суффикс q). Одни и те же 64 бита могут трактоваться одной MMX-командой как 8 байт, другой командой - как 4 слова, и т.д. Тип данных определяется суффиксом команды. Большинство команд технологии MMX обрабатывают данные в циклической арифметике, а некоторые команды используют арифметику с насыщением. Циклическая арифметика. Eсли результат операции выходит за пределы допустимого диапазона, то "лишние" старшие биты результата отбрасываются. Например, сложение байтов 01h и FFh дает 00h. Арифметика с насыщением. Если результат оказался вне допустимого диапазона, то он считается равным граничному значению диапазона. Например, при сложении байтов без знака сумма 01h и FFh считается равной FFh. В арифметике с насыщением MMX-команды сложения, вычитания и упаковки данных могут обрабатывать числа со знаком или без знака. Данные со знаком и без знака имеют различный допустимый диапазон. Следовательно, если используется арифметика с насыщением, то при выходе результата операции за пределы допустимого диапазона в выходной операнд будут записаны различные значения в зависимости от типа данных. Например, если результат превысил 7FFFh, слово со знаком будет считаться равным 7FFFh, a слово без знака - нет. 3. Описание команд MMX-команды сравнения попарно сравнивают элементы данных (байты, 16- или 32- разрядные слова) входного и выходного операндов. В зависимости от результата сравнения соответствующий элемент данных выходного операнда заполняется нулями либо единицами. Эти команды, как и все остальные MMX-команды, не устанавливают флагов (признаков). Команды pcmpeq Команды pcmpeq попарно сравнивают элементы данных (байты, 16- или 32-разрядные слова) входного и выходного операндов. Если элемент данных выходного операнда равен соответствующему элементу входного, такой элемент выходного операнда заполняется единицами. Если равенства нет, он заполняется нулями. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: pcmpeqb, pcmpeqw, pcmpeqd. Команды pcmpgt Команды pcmpgt попарно сравнивают элементы данных (байты, 16- или 32-разрядные слова со знаком) входного и выходного операндов. Если элемент данных выходного операнда больше соответствующего элемента входного, такой элемент выходного операнда заполняется единицами; eсли же он не больше входного, то он заполняется нулями. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: pcmpgtb, pcmpgtw, pcmpgtd. MMX-команды передачи данных movd и movq выполняют копирование: - из одного MMX-регистра в другой, - из MMX-регистра в память и обратно, - из MMX-регистра в целочисленный регистр и обратно (только команда movd). Среди всех MMX-команд только movd и movq могут иметь выходной операнд в памяти; movd - единственная команда, у которой операнд может быть в целочисленном регистре. Команда movd Команда movd копирует 32 бита: - из младших разрядов одного MMX-регистра в младшие разряды другого (старшие разряды заполняются нулями) - из памяти либо из целочисленного регистра в младшие 32 разряда MMX-регистра (старшие разряды заполняются нулями) - из младших разрядов MMX-регистра в память либо в целочисленный регистр. Команда movq Команда movq копирует 64 бита: - из одного MMX-регистра в другой; - из памяти в MMX-регистр; - из MMX-регистра в память. MMX-команды сложения и вычитания работают с упакованными байтами и словами со знаком и без знака, а также с упакованными двойными словами со знаком. Они могут использовать как циклическую арифметику, так и арифметику с насыщением. Команды padd (циклическая арифметика) Команды padd складывают элементы данных (байты, слова или двойные слова) входного и выходного операнда. Если сумма выходит за границу допустимого диапазона, то по правилам циклической арифметики избыток отсчитывается от другой границы диапазона. "Переноса" единицы из одного элемента данных в другой не происходит. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: paddb, paddw, paddd. Команды padds (арифметика с насыщением, данные со знаком) Команды padds складывают элементы данных (байты или слова) входного и выходного операнда. Если сумма выходит за граничное значение допустимого диапазона, то результатом считается это граничное значение. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: paddsb, paddsw. Команды paddus (арифметика с насыщением, данные без знака) Команды paddus складывают элементы данных (байты или слова) входного и выходного операнда. Если сумма выходит за граничное значение допустимого диапазона, то результатом считается это граничное значение. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: paddusb, paddusw. Команды psub (циклическая арифметика) Команды psub вычитают элементы данных (байты, слова или двойные слова) входного операнда из элементов данных выходного операнда. Если результат выходит за границу допустимого диапазона, то по правилам циклической арифметики соответствующее число единиц отсчитывается от другой границы диапазона. "Переноса" единицы из одного элемента данных в другой не происходит. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: psubb, psubw, psubd. Команды psubs (арифметика с насыщением, данные со знаком) Команды psubs вычитают элементы данных (байты или слова) входного операнда из элементов данных выходного операнда. Если разность выходит за граничное значение допустимого диапазона, то результатом считается это граничное значение. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: psubsb, psubsw. Команды psubus (арифметика с насыщением, данные без знака) Команды psubus вычитают элементы данных входного операнда из элементов данных выходного операнда. Если разность выходит за граничное значение допустимого диапазона, то результатом считается это граничное значение. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: psubusb, psubusw. MMX-команды умножения попарно перемножают 16-разрядные слова операндов, что дает четыре 32-разрядных произведения. Команда pmaddwd складывает первое произведение со вторым, а третье с четвертым. Суммы записываются в 32-разрядные слова выходного операнда. Команда pmulhw записывает в 16-разрядные слова выходного операнда старшие разряды каждого из четырех произведений, а pmullw - младшие разряды произведений. Команда pmaddwd (циклическая арифметика) Команда pmaddwd попарно перемножает 16-разрядные слова со знаком входного и выходного операндов. Это дает четыре 32-разрядных произведения. Затем первое произведение складывается со вторым, а третье с четвертым. Суммы записываются в 32- разрядные слова выходного операнда. Если все слова на входе равны 8000h, результатом будет 80000000h (это единственный случай, когда перемножение отрицательных чисел дает отрицательный результат). Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Команда pmulhw (циклическая арифметика) Команда pmulhw попарно перемножает 16-разрядные слова со знаком входного и выходного операндов, что дает четыре 32-разрядных произведения. Старшие разряды произведений записываются в 16-разрядные слова выходного операнда. Младшие разряды произведений теряются. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Команда pmullw (циклическая арифметика) Команда pmullw попарно перемножает 16-разрядные слова со знаком входного и выходного операндов, что дает четыре 32-разрядных произведения. Младшие разряды произведений записываются в 16-разрядные слова выходного операнда. Старшие разряды произведений теряются. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. MMX-команды упаковки преобразуют длинные элементы данных (16- и 32-разрядные слова) в более короткие. Если исходное значение "не помещается" в коротком элементе данных, то происходит "насыщение" - результатом считается граничное значение допустимого диапазона выходного типа данных. Команды распаковки попарно объединяют элементы данных из обоих операндов в более длинные элементы выходного операнда. Этими командами можно пользоваться для повышения числа значащих разрядов при вычислениях. Команды packss Команды packss преобразуют длинные элементы данных (16- и 32-разрядные слова со знаком) в более короткие (байты или 16-разрядные слова со знаком). Если исходное значение было за пределами допустимого диапазона для выходного типа данных, то результатом упаковки считается ближайшее граничное значение диапазона. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: packsswb, packssdw. Команда packuswb Команда packuswb преобразует 16-разрядные слова со знаком из обоих операндов в байты без знака и записывает их в выходной операнд. Если исходное слово со знаком было больше FFh, результатом преобразования считается FFh. Если исходное слово со знаком отрицательно, результатом преобразования считается 00h. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Команды punpckh Команды punpckh попарно объединяют исходные элементы данных (байты, 16- или 32- разрядные слова), находившиеся в старших 32 разрядах обоих операндов. Полученные в результате более длинные элементы данных записываются в выходной операнд. Исходные значения младших разрядов операндов на результат не влияют. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: punpckhbw, punpckhwd, punpckhdq. Команды punpckl Команды punpckl попарно объединяют исходные элементы данных (байты, 16- или 32- разрядные слова), находившиеся в младших 32 разрядах обоих операндов. Полученные в результате более длинные элементы данных записываются в выходной операнд. Исходные значения старших разрядов операндов на результат не влияют. Входной операнд может находиться в MMX-регистре или в памяти; выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: punpcklbw, punpcklwd, punpckldq. MMX-команды сдвига выполняют сдвиг каждого элемента данных (16-, 32- или 64- разрядного слова) в выходном операнде на величину, задаваемую входным операндом. Команды psll (логический сдвиг налево) Команды psll выполняют сдвиг элементов данных (16-, 32- или 64-разрядных слов) в выходном операнде на число бит, задаваемое входным операндом. Освободившиеся младшие разряды заполняются нулями. Входной операнд может быть непосредственным операндом либо находиться в MMX- регистре или в памяти. Выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: psllw, pslld, psllq. Команды psra (арифметический сдвиг направо) Команды psra выполняют сдвиг элементов данных (16- или 32-разрядных слов) в выходном операнде на число бит, задаваемое входным операндом. Если сдвигается положительное число, то освободившиеся старшие разряды заполняются нулями, а если отрицательное, то единицами. Входной операнд может быть непосредственным операндом либо находиться в MMX- регистре или в памяти. Выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: psraw, psrad. Команды psrl (логический сдвиг направо) Команды psrl выполняют сдвиг элементов данных (16-, 32- или 64-разрядных слов) в выходном операнде на число бит, задаваемое входным операндом. Освободившиеся старшие разряды заполняются нулями. Входной операнд может быть непосредственным операндом либо находиться в MMX- регистре или в памяти. Выходной операнд должен находиться в MMX-регистре. Поддерживаются команды: psrlw, psrld, psrlq. Логические MMX-команды выполняют поразрядные логические операции над всеми 64 битами своих операндов. Команда pand (логическoe И) Команда pand вычисляет поразрядное логическое И своих операндов. Входной операнд может находиться в MMX-регистре или в памяти. Выходной операнд должен находиться в MMX-регистре. Команда pandn (логическoe НЕ-И) Команда pandn вычисляет обращение (поразрядное НЕ) выходного операнда, а затем поразрядное логическое И между входным операндом и обращенным значением выходного. Входной операнд может находиться в MMX-регистре или в памяти. Выходной операнд должен находиться в MMX-регистре. Команда por (логическoe ИЛИ) Команда por вычисляет поразрядное логическое ИЛИ своих операндов. Входной операнд может находиться в MMX-регистре или в памяти. Выходной операнд должен находиться в MMX-регистре. Команда pxor (исключающее ИЛИ) Команда pxor вычисляет поразрядное логическое исключающее ИЛИ своих операндов. Входной операнд может находиться в MMX-регистре или в памяти. Выходной операнд должен находиться в MMX-регистре. 4. Примеры использования MMX-команд. ПРИМЕР 1: Абсолютные величины разностей Абсолютные величины разностей чисел используются в алгоритмах распознавания и сжатия в качестве метрики - меры "расстояния" между числами. Идея программы проста: 1. Скопировать элементы исходных векторов из памяти в MMX-регистры командой movq. 2. Вычесть элементы второго вектора из элементов первого в арифметике с насыщением, рассматривая их как числа без знака. Если разность отрицательна, соответствующий элемент выходного операнда станет равным нулю; если разность положительна, она попадет в выходной операнд. 3. Таким же образом вычесть элементы первого вектора из элементов второго. Там, где в предыдущем случае получились нули, теперь будут неотрицательные разности. 4. Вычислить поразрядное логическое ИЛИ от результатов шагов 2 и 3. При этом из каждой пары элементов данных на входе ИЛИ в выходной операнд попадет тот, который не равен нулю. Это и требовалось. ПРИМЕР 2: Скалярное произведение векторов Эта операция часто используется в приложениях линейной алгебры и цифровой обработки сигналов. Скалярное произведение a·b векторов ak и bk (k = 1,..., n) вычисляется так: a·b = a1b1 + a2b2 + ... + anbn Пусть векторы состоят из 16-разрядных слов и находятся в памяти по адресам a_vector и b_vector. Программа будет выполнять следующие шаги: 1. Скопировать 4 слова первого вектора в MMX-регистр командой movq. 2. Скопировать 4 слова второго вектора в MMX-регистр. 3. Попарно перемножить слова и сложить первое произведение со вторым, а третье с четвертым, пользуясь командой pmaddwd. 4. Добавить результаты шага 3 к ранее накопленным суммам командой paddd Эти шаги следует повторить для всех слов исходных векторов (см. программу). 1 loop mowq MM0,[a_vector] 2 movq MM1,[b_vector] 3 pmaddwd MM0,MM1 4 paddd MM7,MM0 5 add [a_vector],8 6 add [b_vector],8 7 sub [count],4 8 jnz loop 9 movq MM0,MM7 10 psrlq MM7,32 11 paddd MM7,MM0 12 movd mem_vdp,MM7 Команды 1-4 реализуют шаги 1-4 Команды 5-8 организуют цикл по всем элементам векторов. Команды 9-11 складывают частичные суммы, накопленные в цикле в старших и младших разрядах регистра MM7. Команда 12 пересылает результат в память. ПРИМЕР 3: Условный выбор фрагмента изображения MMX-команды помогают разрабатывать более эффективные программы компьютерной графики и обработки видеоизображений, во многих случаях позволяя избежать условных переходов. Например, для выделения графического объекта и наложения его на неоднородный фон можно воспользоваться следующими командами: 1. Сформировать маску сравнением цвета точек верхней картинки с синим цветом командой pcmpeqb. 2. Командой pand присвоить значение 0 всем точкам сцены, на которые будет наложен объект "Герой". 3. Командой pandn присвоить значение 0 всем синим точкам исходной картинки с "героем". 4. Выполнить наложение точек объекта на фон командой por. 1 pcmpeqb MM1,MM3 2 pand MM4,MM3 3 pandn MM1,MM3 4 por MM4,MM1 Этот фрагмент программы обрабатывает восемь точек в каждом изображении. Для наложения всего объекта на фон данный фрагмент надо выполнить в цикле для всех точек изображения. 1. Команда pcmpeqb формирует маску: точки, соответствующие "герою" заполняются нулями, а окружающие точки - единицами. 2. Команда pand присваивает значение 0 всем точкам фона, на которые попадет "герой". 3. Команда pandn присваивает значение 0 всем синим точкам картинки с "героем". 4. Команда por выпоняет наложение "героя" на фон. ПРИМЕР 4: Распаковка с "размножением" знака Часто бывает нужно преобразовать короткие данные в более длинные. Если это слова без знака, можно воспользоваться одной из команд группы punpck, позаботившись, чтобы в старшие разряды результатов сразу попали нули. Если же надо повысить разрядность слов со знаком, можно действовать следующим образом: 1. Распаковать слова из младших 32 разрядов командой punpcklwd, так, чтобы знаковый бит попал в самый старший разряд двойного слова-результата. 2. Распаковать слова из старших 32 разрядов командой punpckhwd (в другой регистр). 3. Выполнить арифметический сдвиг полученных двойных слов направо командой psrad. При этом знаковый бит в каждом слове размножится, и 32-разрядные слова со знаком будут иметь те же численные значения, что и исходные 16-разрядные слова со знаком.