本节包括几个简单的例子来帮助你开始编写应用程序,最终目的是提供一些经常使用的、简单的低级操作。每个例子都使用最少的指令数来达到奔腾和P6系统处理器的最佳性能。
每个例子包括:
一个简短的描述
核心代码
必要的解释
考虑到你可能会将这些例子插入到更长的代码序列中,故这些例子中不涉及有关调度问题。
5.1 无符号分组
MMX™技术提供了几条用来将MMX™寄存器中的数据成组和分组的指令。分组指令可用于对一个无符号数进行零扩展(zero-extend)。下例假设源操作数是一个字组数据(16位)类型。
输入:
MM0: 源值
MM7: 0
如果需要,可用一个局部变量代替MM7寄存器。
输出:
MM0: 由2个低端字数据经零扩展形成的两个32位双字。
MM1: 由2个高端字数据经零扩展形成的两个32位双字。
MOVQ MM1, MM0 ;源数据复制
PUNPCKLWD MM0, MM7 ;将两个低端字数据分组为两个32位双字
PUNPCKHWD MM1, MM7 ;将两个高端字数据分组为两个32位双字
5.2 有符号分组
当对一个分组时,应对有符号数进行符号扩展(sign-extend)。这一点与上述零扩展不同。下例假设源操作数是一个成组字数据(16位)类型。
输入:
MM0: 源值
输出:
MM0: 由2个低端字数据经符号扩展形成的两个32位双字。
MM1: 由2个高端字数据经符号扩展形成的两个32位双字。
PUNPCKHWD MM1, MM0 ;将源数据的两个高端字数据分组为
;目标数据的第2个和第4个字数据
PUNPCKHLD MM0, MM0 ;将源数据的两个低端字数据分组为
;目标数据的第2个和第4个字数据
PSRAD MM0, 16 ;将源数据的两个低端字数据
;经符号扩展形成的两个32位双字
PSRAD MM1, 16 ;将源数据的两个高端字数据
;经符号扩展形成的两个32位双字
5.3 饱和模式下的交错成组
PACK指令按预先定义的顺序将两个值合并到目的寄存器。特别说明的是,PACKSSDW指令将源操作数两个有符号双字和目的操作数的两个有符号双字合并成目的寄存器中的四个有符号字。如图5一1所示:
图5-1 PACKSSDW mm, mm/mm64指令示例
下例将两个值交错送入目的寄存器,如图5一2所示。
图5-2 饱和模式下的交错成组示例
本例中源操作数为有符号的双字,结果是交错的有符号字。成组指令不论是否是饱和模式都可执行。
输入:
MM0: 第一个有符号源值
MM1: 第二个有符号源值
输出:
MM0: 第一、三字来自MM0中的饱和模式有符号双字,
第二、四字来自MM1中的饱和模式有符号双字。
PACKSSDW MM0, MM0 ;饱和模式有符号成组
PACKSSDW MM1, MM1 ;饱和模式有符号成组
PUNPKLWD MM0, MM1 ;将操作数低端16位值交错
成组指令总是假设源操作数为有符号数。目的寄存器中的结果由执行操作的成组指令定义。例如,PACKSSDW指令将两个源数据中各自的两个有符号32位值形成目的寄存器中的四个饱和的16位有符号值。另一方面,PACKUSWB指令将两个源数据中各自的四个有符号16位值形成目的寄存器中的四个饱和的8位无符号值。有关MMX™指令集的完整说明请见《Intel体系结构MMX™技术程序员参考手册》(Inte1 Architecture MMX™ Technology Programmers Reference Manual),(序号243007)。
5.4 非饱和模式下的交错成组
本例除结果字为非饱和的外,同上例相似。另外,为防止溢出,本操作只使用每个双字的低16位。
输入:
MM0: 有符号源值
MM1: 有符号源值
输出:
MM0: 第一、三字来自MM0中的双字的低16位,
第二、四字来自MM1中的的双字的低16位。
PSLLD MM1, 16 ;将每个双字值中的LSB移16位
;到MSB位置
PAND MM0, {0, FFFF, 0, FFFF}
;将每个双字值的16MSB标记为0
POR MM0, MM1 ;合并两个操作数
5.5 非交错分组
分组指令将目的操作数和源操作数的数据元素交错合并到目的寄存器中。下例非交错地将两个操作数合并到目的寄存器中。例如,从源数据1中的字组数据类型中取两个相邻元素,并将该值放到结果的低32位中。然后从源数据2中的字组数据类型中取两个相邻元素,并将该值放到结果的高32位中。目的寄存器的一种组合形式如图5一3所示。
目的寄存器的另一种相反的组合如图5一4所示。
图5-4 MM1中的非交错分组的结果
下例将两个字组的源数据按非交错方式分组。其实现方法为用将双字变为四字的指令代替将字变为双字的分组指令。
输入:
MM0: 字组源值
MM1: 字组源值
输出:
MM0: 包含两个非交错的初始源值的低端字
MM2: 包含两个非交错的初始源值的高端字
MOVQ MM2, MM0 ;复制源值1
PUNPCKLDQ MM0, MM1 ;用MMl的两个低端字替换MM0的两个高端字,
;保留MM0中的两个低端字
PUNPCKHDQ MM2, MM1 ;将MM2的两个高端字移到低端,
;将MM1的两个高端字送入MM2的两个高端字