GCCの機能拡張とベクトル演算
MMX,SSE,SSE2の拡張機能プログラミングノート
陳 謙 Copyright (c) 2003 Qian CHEN
chen@sys.wakayama-u.ac.jp
目次
1 はじめに
1.1 プログラミング環境
1.2 ダウンロードとインストール
2 CPU機能の調査
3 新しいデータ型
3.1 ベクトル型
3.2 型変換とそのためのデータ型
4 GCCがサポートするベクトル演算
5 拡張機能を利用するための内蔵関数
6 MMX拡張機能
6.1 MMX拡張機能を利用する時の前処理と後処理
6.2 MMX状態クリア
6.3 飽和処理ありパック処理
6.4 アンパック処理
6.5 並列四則演算
6.6 シフト処理
6.7 ビットごと論理演算
6.8 比較
6.9 0値ベクトル
7 SSE拡張機能
7.1 スカラー四則演算
7.2 その他のスカラー演算
7.3 並列四則演算
7.4 その他の並列演算
7.5 ビットごと論理演算
7.6 スカラー比較1(戻り値はビットマスク)
7.7 並列比較
7.8 順序ありスカラー比較(戻り値は論理値)
7.9 順序なしスカラー比較(戻り値は論理値)
7.10 型変換
7.11 組み換え
7.12 アンパック
7.13 データの移動
7.14 コントロールレジスタの操作
7.15 SSE拡張MMX機能
7.15.1 16ビットデータのの取り出し
7.15.2 16ビットデータの挿入
7.15.3 最大/最小値
7.15.4 符号ビットの取り出し
7.15.5 符号なしshortの掛算
7.15.6 組み換え
7.15.7 マスクによるデータの移動
7.15.8 平均値
7.15.9 差の絶対値の合計
7.16 非一時保存
7.17 セーブ保存柵
7.18 4x4行列の転置
8 SSE2拡張機能
8.1 スカラー四則演算
8.2 その他のスカラー演算
8.3 並列四則演算
8.4 その他の並列演算
8.5 ビットごと論理演算
8.6 スカラー比較1(戻り値はビットマスク)
8.7 並列比較
8.8 順序ありスカラー比較(戻り値は論理値)
8.9 順序なしスカラー比較(戻り値は論理値)
8.10 型変換
8.11 組み換え
8.12 アンパック
8.13 データの移動
8.14 SSE2拡張MMX機能
8.14.2 アンパック処理
8.14.3 並列四則演算
8.14.4 シフト処理
8.14.5 ビットごと倫理演算
8.14.6 比較
8.14.7 0値ベクトル
8.14.8 16 ビットデータの取り出し
8.14.9 16ビットデータの挿入
8.14.10 最大/最小値
8.14.11 符号ビットの取り出し
8.14.12 組み換え
8.14.13 マスクによるデータの移動
8.14.14 平均値
8.14.15 差の絶対値の合計
8.15 非一時保存
8.16 キャッシュのフラッシュ
8.17 柵
1 はじめに
GCC(Gnu Compiler Collection)は,最新のCPUやプログラミング環境を有効に利用するために,プログラミング言語の仕様に対して,さまざまな機能拡張を施しています.本資料は,X86系CPUにおけるベクトル演算機能をGnu Cから利用する方法を紹介します.X86系CPUにはベクトル演算に関連する機能として,MMX,SSE,SSE2という3つの拡張機能があります.本資料ではそれぞれを利用する環境と方法について説明します.
1.1 プログラミング環境
本資料はLinux環境を対象としており,紹介する内容の開発とテストはLinux環境で行われています.使用するLinuxのカーネルは2.4.21で,GCCのバージョンは3.3です.本資料で紹介する内容を利用する環境として,2.4.19以降のバージョンのカーネルとバージョン3.3以降のGCCがインストールしていることが望ましいです.GCCに関する情報はhttp://gcc.gnu.org/から得ることができます.
1.2 ダウンロードとインストール
1.2.1 ダウンロード
本資料で紹介する内容を利用するために,libxmmをインストールする必要があります.libxmmがここからダウンロードできます.
1.2.2 インストール
ダウンロードしたファイルを適当なディレクトリに保存して,そこで下記の命令を実行してファイルを展開してください.
tar xvzf libxmm.tgz
cd libxmm
インストールするときに,root権限が必要です.root権限を持っている方なら,su命令を使って,rootユーザになってから下記の命令を実行し,root権限を持っていなければ,Makefileをテキストエディターで開き,prefix=/usr/localの行の/usr/localの部分を自分のホームディレクトリの名前に書き換えてから,下記の命令を実行してください.
make clean
make install
これでインストールが完了します.お使いの環境,設定によって,自分が書いたプログラムを次のようにコンパイル必要があるかもしれません.(ここで,Cのソースプログラムを a.c と仮定します.)
cc -I/usr/local/include -L/usr/local/lib -O2 -msse2 -o a a.c -lxmm
あるいは,
cc -Iホームディレクトリ名/include -Lホームディレクトリ名/lib -O2 -msse2 -o a a.c -lxmm
2.CPU機能の調査
使用中のCPUがMMX,SSE,SSE2の各機能のサポートする状況は下記の関数を用いて調べるすることができます.
#include <xmmx.h>
void cpufeature(int *HasMMX, int *HasSSE, int *HasSSE2);
関数が実行した後,*HasMMX, *HasSSE, *HasSSE2の値が1であれば,MMX,SSE,SSE2の機能利用できます.そうでなければ,利用できません.
3. 新しいデータ型
拡張機能・ベクトル演算機能を利用するために,2種類のデータを新たに用意しています.
3.1 ベクトル型
ベクトル型とは複数の同じ型の単一要素のベクトルを表現するもので,同一型の要素を持つ配列と似ています.
用意されているベクトル型とその意味は以下の通りです.
型名 |
内容 |
説明 |
v1di |
1個の64ビット整数 |
long long あるいはunsigned long longに相当> |
v2si |
2個の32ビット整数 |
int [2] あるいはunsigned int [2]に相当 |
v4hi |
4個の16ビット整数 |
short [4] あるいはunsigned short [4]に相当 |
v8qi |
8個の 8ビット整数 |
signed char [8] あるいはunsigned char [8]に相当 |
v2di |
2個の64ビット整数 |
long long [2] あるいはunsigned long long [2]に相当 |
v4si |
4個の32ビット整数 |
int [4] あるいはunsigned int [4]に相当 |
v8hi |
8個の16ビット整数 |
short [8] あるいはunsigned short [8]に相当 |
v16qi |
16個の8ビット整数 |
signed char [16] あるいはunsigned char [16]に相当 |
v4sf |
4個の単精度浮動小数点数 |
float [4] に相当する |
v2df |
2個の倍精度浮動小数点数 |
double [2]に相当する |
これらのデータ型の変数を宣言することが可能で,関数の中,関数の引数,そして関数の戻り値として使うこともできます.また,サイズが一致する型であれば,異なるベクトル型同士,あるいはベクトル型と他の型との間の型変換(キャスト)が可能です.
後で紹介する内蔵関数のために,二つのデータ型mm_tとxmm_tが定義していあり,それぞれはv4hiとv4sfの別名です.これらの型を利用するために, xmm.h ファイルをインクルードする必要があります.
3.2 型変換とそのためのデータタイプ
ベクトル型のデータを各要素に,あるいは複数の要素データをベクトル型のデータに変換するために,下記二つの共同体が定義しています.
typedef union {
mm_t mm;
long long di;
unsigned long long udi;
int si[2];
unsigned int usi[2];
short hi[4];
unsigned short uhi[4];
signed char qi[8];
unsigned char uqi[8];
} __attribute__ ((aligned(8))) umm_t;
typedef union {
xmm_t xmm;
long long di[2];
unsigned long long udi[2];
int si[4];
unsigned int usi[4];
short hi[8];
unsigned short uhi[8];
signed char qi[16];
unsigned char uqi[16];
double df[2];
float sf[4];
} __attribute__ ((aligned(16))) uxmm_t;
その使用例は下記に示します.
1.4個のshort型の変数a,b,c,dから1個のv4hi型変数mに変換します.
short a, b, c, d;
v4hi m;
umm_t u;
u.hi[0] = a;
u.hi[1] = b;
u.hi[2] = c;
u.hi[3] = d;
m = (v4hi)u.mm;
2.v2df型の変数mから2個のdouble要素を取り出し,変数aとbに代入ます.
double a, b;
v2df m;
uxmm_t u;
u.xmm = (xmm_t)m;
a = u.df[0];
b = u.df[1];
4.GCCがサポートするベクトル演算
GCCがサポートするベクトル演算四つです:
足し算: 計算結果=対応する要素の和を要素とする同じ型のベクトル
引き算: 計算結果=対応する要素の差を要素とする同じ型のベクトル
掛け算: 計算結果=対応する要素の積を要素とする同じ型のベクトル
割り算: 計算結果=対応する要素の商を要素とする同じ型のベクトル
例:
v4hi a, b, c;
c = a * b;
このコードは,下記のコードと同じ結果となります.
umm_t u1, u2;
v4hi a, b, c;
u1.mm = (mm_t)a;
u2.mm = (mm_t)b;
u1.hi[0] += u2.hi[0];
u1.hi[1] += u2.hi[1];
u1.hi[2] += u2.hi[2];
u1.hi[3] += u2.hi[3];
c = (v4hi)u1.mm;
もし,使用しているCPUが指定した型をサポートしなければ,GCCはその演算をエミュレートするコードを生成します.(結果が正しいが、実行速度が遅くなります)
5 拡張機能を利用するための内蔵関数
MMX,そして後で紹介するSSE,SSE2が提供する四則演算以外のベクトル演算・処理の機能は,GCCの内蔵関数を使って利用することができます.
内蔵関数の機能を説明するために下記の表記法を利用します.
ベクトル型データの表記法: { 要素0の値, 要素1の値, ... }
ベクトル型変数の要素の表記法:
ベクトル型変数 |
符号あり要素 |
符号なし要素 |
v1di a |
a.di |
a.udi |
v2si a |
a.si[0], a.si[1] |
a.usi[0], a.usi[1] |
v4hi a |
a.hi[0], ..., a.hi[3] |
a.uhi[0], ..., a.uhi[3] |
v8qi a |
a.qi[0], ..., a.qi[7] |
a.uqi[0], ..., a.uqi[7] |
v2di a |
a.di[0], a.di[1] |
a.udi[0], a.udi[1] |
v4si a |
a.si[0], ..., a.si[3] |
a.usi[0], ..., a.usi[3] |
v8hi a |
a.hi[0], ..., a.hi[7] |
a.uhi[0], ..., a.uhi[7] |
v16qi a |
a.qi[0], ..., a.qi[15] |
a.uqi[0], ..., a.uqi[15] |
v4sf a |
a.sf[0], ..., a.sf[3] |
なし |
v2df a |
a.df[0], a.df[1] |
なし |
6 MMX拡張機能
MMX拡張機能はPentium-MMX以降のX86系CPUに搭載されており,それより旧式のCPU(i386, i486, Pentium, PentiumProなど)では利用できません.MMX機能拡張がサポートするベクトル型はv8qi, v4hi, v2si, v1diとv4hiの別名であるmm_tです.それは全部64ビットのデータです.
6.1 MMX拡張機能を利用する時の前処理と後処理
#include <xmm.h>
void begin_mmx(I87stack *pstk);
void end_mmx(I87stack *pstk);
MMX拡張機能と64ビットのベクトル型のデータを用いるSSE,SSE2の拡張機能を利用する前に,begin_mmx() を呼び出す必要があります.MMX等の拡張機能を利用した後,(SSE,SSE2ではなく,いわゆるX87コード)浮動小数点演算を行なう前に,直前にbegin_mmx()に渡した引数を使ってend_mmx()を呼び出さなければなりません.
例:
double f(double x, double y, long long a, long long b)
{
I87stack s;
v4hi ma, mb;
double fa;
/* 浮動小数点演算 */
fa = x + y;
/* MMX拡張機能を利用する前に */
begin_mmx(&s);
/* MMX拡張機能を利用する処理 */
ma = (v4hi)a;
mb = (v4hi)b;
a = (long long)(ma+mb);
/* MMX拡張機能を利用した後,浮動小数点演算を行なう前に */
end_mmx(&s);
/* 浮動小数点演算 */
printf("fa=%f\n", fa);
if (a == 0)
return(fa);
else
return(-fa);
}
注:
MMX拡張機能と(SSE,SSE2でない)浮動小数点数演算は,CPU内部の同じレジスタ群(レジスタスタック)を利用し行います.しかし,MMX拡張機能のベクトルデータ型と浮動小数点数のデータ型との互換性はなく,両者は共存できません.そのため,MMX拡張機能を利用する前に,浮動小数点演算用のレジスタの内容を( begin_mmx()を使って)退避させて,MMX拡張機能を利用した後,浮動小数点数演算を再開する前に,MMXレジスタの内容を破棄して,前もって退避させた浮動小数点演算用のレジスタの内容を( end_mmx()を使って)復元しなければいけません.
6.2 MMX状態クリア
void mm_emms(void);
機能:MMXレジスタのクリア.begin_mmx(), end_mmx()を利用する場合,直接に使う必要は
ありません.
6.3 飽和処理ありパック処理
mm_t mm_packsswb(mm_t m1, mm_t m2);
機能:二つのv4hi型の引数(8個のshortの値)を1個のv8qi型の値(8個のsigned
char型の値)
に変換します.
戻値=(v8qi){ (signed char)m1.hi[0], ..., (signed char)m1.hi[3],
(signed char)m2.hi[0], ..., (signed char)m2.hi[3] }
mm_t mm_packssdw(mm_t m1, mm_t m2);
機能:二つのv2si型の引数(4個のintの値)を1個のv4hi型の値(4個のshort型の値)に変換し
ます.
戻値=(v4hi){ (short)m1.si[0], (short)m1.si[1], (short)m2.si[0], (short)m2.si[1] }
mm_t mm_packuswb(mm_t m1, mm_t m2);
機能:二つのv4hi型の引数(8個のunsigned shortの値)を1個のv8qi型の値(8個の
unsigned char型の値)に変換します.
戻値=(v8qi){ (unsigned char)m1.uhi[0], ..., (unsigned char)m1.uhi[3],
(unsigned char)m2.uhi[0], ..., (unsigned char)m2.uhi[3] }
注: 飽和処理: ある値Vをあるデータ型Xに変換するとき,もしVはXが表現できる最大(最小)
の値よりも大きい(小さい)とき, Vをその最大(最小)値に変換してからXに変換する処理
のこと.
6.4 アンパック処理
mm_t mm_punpckhbw(mm_t m1, mm_t m2);
機能:m1の上位4個のcharを下位8ビット,m2の上位4個charを上位8ビットとする4個のshort
に変換します.
戻値=(v4hi){ {m1.qi[4],m2.qi[4]}, ..., {m1.qi[7],m2.qi[7] }
mm_t mm_punpckhwd(mm_t m1, mm_t m2);
機能:m1の上位2個のshortを下位16ビット,m2の上位2個shortを上位16ビットとする2個の
intに変換します.
戻値=(v2si){ {m1.hi[2],m2.hi[2]}, {m1.hi[3],m2.hi[3]} }
mm_t mm_punpckhdq(mm_t m1, mm_t m2);
機能:m1の上位intを下位32ビット,m2の上位intを上位32ビットとするlong
longに変換し
ます
戻値=(v1di){ m1.si[1], m2.si[1] }
mm_t mm_punpcklbw(mm_t m1, mm_t m2);
機能:m1の下位4個のcharを下位8ビット,m2の下位4個のcharを上位8ビットとする4個の
shortに変換します.
戻値=(v4hi){ {m1.qi[0], m2.qi[0]},..., {m1.qi[3], m2.qi[3]} }
mm_t mm_punpcklwd(mm_t m1, mm_t m2);
機能:m1の下位2個のshortを下位16ビット,m2の下位2個のshortを上位16ビットとする2個
のintに変換します.
戻値=(v2si){ {m1.hi[0], m2.hi[0]}, {m1.hi[1], m2.hi[1]} }
mm_t mm_punpckldq(mm_t m1, mm_t m2);
機能:m1の下位intを下位32ビット,m2の下位intを上位32ビットとするlong
longに変換し
ます.
戻値=(v1di){ m1.si[0], m2.si[0] }
6.5 並列四則演算
mm_t mm_paddb(mm_t m1, mm_t m2);
機能:並列v8qi型(signed char, unsigned char両方)の足し算.
戻値=(v8qi)m1+(v8qi)m2
mm_t mm_paddw(mm_t m1, mm_t m2);
機能:並列v4hi型(short, unsigned short両方)の足し算.
戻値=(v4hi)m1+(v4hi)m2
mm_t mm_paddd(mm_t m1, mm_t m2);
機能:並列v2si型(int, unsigned int両方)の足し算.
戻値=(v2si)m1+(v2si)m2
mm_t mm_paddq(mm_t m1, mm_t m2);
機能:v1di型(long long, unsigned long long両方)の足し算.
戻値=(v1di)m1+(v1di)m2
mm_t mm_paddsb(mm_t m1, mm_t m2);
機能:飽和処理ありsigned charの並列足し算.
戻値=(v8qi){ m1.qi[0]+m2.qi[0], ..., m1.qi[7]+m2.qi[7] }
mm_t mm_paddsw(mm_t m1, mm_t m2);
機能:飽和処理ありshortの並列足し算.
戻値=(v4hi){ m1.hi[0]+m2.hi[0], ..., m1.hi[3]+m2.hi[3] }
mm_t mm_paddusb(mm_t m1, mm_t m2);
機能:飽和処理ありunsigned charの並列足し算.
戻値=(v8qi){ m1.uqi[0]+m2.uqi[0], ..., m1.uqi[7]+m2.uqi[7] }
mm_t mm_paddusw(mm_t m1, mm_t m2);
機能:飽和処理ありunsigned shortの並列足し算.
戻値=(v4hi){ m1.uhi[0]+m2.uhi[0], ..., m1.uhi[3]+m2.uhi[3] }
mm_t mm_psubb(mm_t m1, mm_t m2);
機能:並列v8qi型(signed char, unsigned char両方)の引き算.
戻値=(v8qi)m1-(v8qi)m2
mm_t mm_psubw(mm_t m1, mm_t m2);
機能:並列v4hi型(short, unsigned short両方)の引き算.
戻値=(v4hi)m1-(v4hi)m2
mm_t mm_psubd(mm_t m1, mm_t m2);
機能:並列v2si型(int, unsigned int両方)の引き算.
戻値=(v2si)m1-(v2si)m2
mm_t mm_psubq(mm_t m1, mm_t m2);
機能:v1di型(long long, unsigned long long両方)の引き算
戻値=(v1di)m1-(v1di)m2
mm_t mm_psubsb(mm_t m1, mm_t m2);
機能:飽和処理ありsigned charの並列引き算
戻値=(v8qi){ m1.qi[0]-m2.qi[0], ..., m1.qi[7]-m2.qi[7] }
mm_t mm_psubsw(mm_t m1, mm_t m2);
機能:飽和処理ありshortの並列引き算
戻値=(v4hi){ m1.hi[0]-m2.hi[0], ..., m1.hi[3]-m2.hi[3] }
mm_t mm_psubusb(mm_t m1, mm_t m2);
機能:飽和処理ありunsigned charの並列引き算
戻値=(v8qi){ m1.uqi[0]-m2.uqi[0], ..., m1.uqi[7]-m2.uqi[7] }
mm_t mm_psubusw(mm_t m1, mm_t m2);
機能:飽和処理ありunsigned shortの並列引き算
戻値=(v4hi){ m1.uhi[0]-m2.uhi[0], ..., m1.uhi[3]-m2.uhi[3] }
mm_t mm_pmaddwd(mm_t m1, mm_t m2);
機能:shortの積和の計算.結果は2個のint
戻値=(v2si){ m1.hi[0]*m2.hi[0]+m1.hi[1]*m2.hi[1], m1.hi[2]*m2.hi[2]+m1.hi[3]*m2.hi[3] }
mm_t mm_pmulhw(mm_t m1, mm_t m2);
機能:shortの並列掛け算.結果の上位16ビットが保存される
戻値=(v4hi){ (m1.hi[0]*m2.hi[0])>>16, ..., (m1.hi[3]*m2.hi[3])>>16
}
mm_t mm_pmullw(mm_t m1, mm_t m2);
機能:shortの並列掛け算.結果の下位16ビットが保存される
戻値=(v4hi){ (m1.hi[0]*m2.hi[0])&0xffff, ..., (m1.hi[3]*m2.hi[3])&0xffff
}
6.6 シフト処理
mm_t mm_psllw(mm_t m, mm_t n);
機能:v4hiベクトルの左シフト.カウンタはmm_t型
戻値=(v4hi){ m.hi[0] << n, ..., m.hi[3] << n }
mm_t mm_psllw_i(mm_t m, int n);
機能:v4hiベクトルの左シフト.カウンタはint型定数
戻値=(v4hi){ m.hi[0] << n, ..., m.hi[3] << n }
mm_t mm_pslld(mm_t m, mm_t n);
機能:v2siベクトルの左シフト.カウンタはmm_t型
戻値=(v2si){ m.si[0] << n, m.si[1] << n }
mm_t mm_pslld_i(mm_t m, int n);
機能:v2siベクトルの左シフト.カウンタはint型定数
戻値=(v2si){ m.si[0] << n, m.si[1] << n }
mm_t mm_psllq(mm_t m, mm_t n);
機能:v1diベクトルの左シフト.カウンタはmm_t型
戻値=(v1di){ m.di[0] << n }
mm_t mm_psllq_i(mm_t m, int n);
機能:v1diベクトルの左シフト.カウンタはint型定数
戻値=(v1di){ m.di[0] << n }
mm_t mm_psraw(mm_t m, mm_t n);
機能:v4hiベクトルの右算術シフト.カウンタはmm_t型
戻値=(v4hi){ (m.hi[0] >> n, ..., m.hi[3] >> n }
mm_t mm_psraw_i(mm_t m, int n);
機能:v4hiベクトルの右算術シフト.カウンタはint型定数
戻値=(v4hi){ (m.hi[0] >> n, ..., m.hi[3] >> n }
mm_t mm_psrad(mm_t m, mm_t n);
機能:v2siベクトルの右算術シフト.カウンタはmm_t型
戻値=(v2si){ m.si[0] >> n, m.si[1] >> n }
mm_t mm_psrad_i(mm_t m, int n);
機能:v2siベクトルの右算術シフト.カウンタはint型定数
戻値=(v2si){ m.si[0] >> n, m.si[1] >> n }
mm_t mm_psrlw(mm_t m, mm_t count);
機能:v4hiベクトルの右論理シフト.カウンタはmm_t型
戻値=(v4hi){ m.uhi[0] >> n, ..., m.uhi[3] >> n }
mm_t mm_psrlw_i(mm_t m, int n);
機能:v4hiベクトルの右論理シフト.カウンタはint型定数
戻値=(v4hi){ m.uhi[0] >> n, ..., m.uhi[3] >> n }
mm_t mm_psrld(mm_t m, mm_t n);
機能:v2siベクトルの右論理シフト.カウンタはmm_t型
戻値=(v2si){ m.usi[0] >> n, m.usi[1] >> n }
mm_t mm_psrld_i(mm_t m, int n);
機能:v2siベクトルの右論理シフト.カウンタはint型定数
戻値=(v2si){ m.usi[0] >> n, m.usi[1]>> n }
mm_t mm_psrlq(mm_t m, mm_t n);
機能:v1diベクトルの右論理シフト.カウンタはmm_t型
戻値=(v1di){ m.udi >> n }
mm_t mm_psrlq_i(mm_t m, int n);
機能:v1diベクトルの右論理シフト.カウンタはint型定数
戻値=(v1di){ m1.udi >> n }
6.7 ビットごと論理演算
mm_t mm_pand(mm_t m1, mm_t m2);
機能:ビットごと論理積
戻値=(v1di){ m1.di & m2.di }
mm_t mm_pandn(mm_t m1, mm_t m2)
機能:ビットごと反転論理積
戻値=(v1di){ ~m1.di & m2.di }
mm_t mm_por(mm_t m1, mm_t m2)
機能:ビットごと論理和
戻値=(v1di){ m1.di | m2.di }
mm_t mm_pxor(mm_t m1, mm_t m2)
機能:ビットごと排他論理和
戻値=(v1di){ m1.di ^ m1.di }
6.8 比較
mm_t mm_pcmpeqb(mm_t m1, mm_t m2);
機能:v8qiベクトルの等しさ比較
戻値=(v8qi){ (m1.qi[0]==m2.qi[0])*0xff, ..., (m1.qi[7]==m2.qi[7])*0xff }
mm_t mm_pcmpgtb(mm_t m1, mm_t m2);
機能:v8qiベクトルの大なり比較
戻値=(v8qi){ (m1.qi[0]>m2.qi[0])*0xff, ..., (m1.qi[7]>m2.qi[7])*0xff }
mm_t mm_pcmpeqw(mm_t m1, mm_t m2);
機能:v4hiベクトルの等しさ比較
戻値=(v4hi){ (m1.hi[0]==m2.hi[0])*0xffff, ..., (m1.hi[3]==m2.hi[3])*0xffff }
mm_t mm_pcmpgtw(mm_t m1, mm_t m2);
機能:v4hiベクトルの大なり比較
戻値=(v4hi){ (m1.hi[0]>m2.hi[0])*0xffff, ..., (m1.hi[3]>m2.hi[3])*0xffff }
mm_t mm_pcmpeqd(mm_t m1, mm_t m2);
機能:v2siベクトルの等しさ比較
戻値=(v2si){ (m1.si[0]==m2.si[0])*0xffffffff, (m1.si[1]==m2.si[1])*0xffffffff }
mm_t mm_pcmpgtd(mm_t m1, mm_t m2);
機能:v2siベクトルの大なり比較
戻値=(v2si){ (m1.si[0]>m2.si[0])*0xffffffff, (m1.si[1]>m2.si[1])*0xffffffff }
6.9 0値ベクトル
mm_t mm_setzero(void);
機能:全ビット0のmm_t型の値を返す.
戻値=(v1di){ 0LL }
7 SSE拡張機能
SSE拡張機能はPentiumIII以降のX86系CPUに搭載されていて,それより旧式のCPU(i386, i486, Pentium, PentiumPro, Pentium-MMX, PeniumIIなど)では利用できません.SSE拡張機能主に単精度の浮動小数点データの並列演算をサポートし,使用するベクトル型はMMX拡張機能がサポートするものの他に,v4sfとその別名であるxmm_tです.それは128ビットのデータです.
7.1 スカラー四則演算
xmm_t se_addss(xmm_t a, xmm_t b);
xmm_t se_subss(xmm_t a, xmm_t b);
xmm_t se_mulss(xmm_t a, xmm_t b);
xmm_t se_divss(xmm_t a, xmm_t b);
機能:v4sf型の引数aとbの最下位のfloat値同士の四則演算.
戻値={ a.sf[0] 演算子 b.sf[0], a.sf[1], a.sf[2], a.sf[3] }
7.2 その他のスカラー演算
xmm_t se_sqrtss(xmm_t a);
機能:v4sf型の引数の最下位のfloat値の平方根.
戻値={ sqrt(a.sf[0]), a.sf[1], a.sf[2], a.sf[3] }
xmm_t se_rcpss(xmm_t a);
機能:v4sf型の引数の最下位のfloat値の逆数の近似.結果の相対誤差 <
0.0336%
戻値={ 1.0/a.sf[0], a.sf[1], a.sf[2], a.sf[3] }
xmm_t se_rsqrtss(xmm_t a);
機能:v4sf型の引数の最下位のfloat値の平方根の逆数の近似.結果の相対誤差
< 0.0336%
戻値={ 1.0/sqrt(a.sf[0]), a.sf[1], a.sf[2], a.sf[3] }
xmm_t se_minss(xmm_t a, xmm_t b);
xmm_t se_maxss(xmm_t a, xmm_t b);
機能:v4sf型の引数aとbの最下位のfloat値の中の最小値/最大値.
戻値={ 最小/最大(a.sf[0], b.sf[0]), a.sf[1], a.sf[2], a.sf[3] }
7.3 列四則演算
xmm_t se_addps(xmm_t a, xmm_t b);
xmm_t se_subps(xmm_t a, xmm_t b);
xmm_t se_mulps(xmm_t a, xmm_t b);
xmm_t se_divps(xmm_t a, xmm_t b);
機能:引数aとbの4個のfloat値同士の並列四則演算
戻値={ a.sf[0] 演算子 b.sf[0], ..., a.sf[3] 演算子 b.sf[3] }
7.4 その他の並列演算
xmm_t se_sqrtps(xmm_t a);
機能:並列平方根
戻値={ sqrt(a.sf[0]), ..., sqrt(a.sf[3]) }
xmm_t se_rcpps(xmm_t a);
機能:並列逆数.結果の相対誤差 < 0.0336%
戻値={ 1.0/a.sf[0], …, 1.0/a.sf[3] }
xmm_t se_rsqrtps(xmm_t a);
機能:並列平方根の逆数.結果の相対誤差 < 0.0336%
戻値={ 1.0/sqrt(a.sf[0]), ..., 1.0/sqrt(a.sf[3]) }
xmm_t se_minps(xmm_t a, xmm_t b);
xmm_t se_maxps(xmm_t a, xmm_t b);
機能:並列最小値/最大値.
戻値={ 最小/最大(a.sf[0], b.sf[0]), ..., 最小/最大(a.sf[3], b.sf[3]) }
7.5 ビットごと論理演算
xmm_t se_andps(xmm_t a, xmm_t b);
xmm_t se_andnps(xmm_t a, xmm_t b);
xmm_t se_orps(xmm_t a, xmm_t b);
xmm_t se_xorps(xmm_t a, xmm_t b);
機能:ビットごと論理積,否定論理積,論理和,排他的論理和
戻値(se_andps)={ a.di[0] & b.di[0], a.di[1] & b.di[1] }
戻値(se_andnps)={ ~a.di[0] & b.di[0], ~a.di[1] & b.di[1] }
戻値(se_orps)={ a.di[0] | b.di[0], a.di[1] | b.di[1] }
戻値(se_xorps)={ a.di[0] ^ b.di[0], a.di[1] ^ b.di[1] }
7.6 カラー比較1(戻り値はビットマスク)
xmm_t se_cmpeqss(xmm_t a, xmm_t b);
xmm_t se_cmpltss (xmm_t a, xmm_t b);
xmm_t se_cmpless(xmm_t a, xmm_t b);
xmm_t se_cmpneqss(xmm_t a, xmm_t b);
xmm_t se_cmpnltss(xmm_t a, xmm_t b);
xmm_t se_cmpnle_ss(xmm_t a, xmm_t b);
xmm_t se_cmpordss(xmm_t a, xmm_t b);
xmm_t se_cmpunordss(xmm_t a, xmm_t b);
機能:v4sf型の引数aとbの最下位のfloat値の比較(等しい,小なり,以下,
等しくない,小なりでない,以下でない,順序付け可能,順序付け不能).
比較結果が“真”の場合,下位32ビットがすべて1に,さもなければ0に
セットされます.
戻値(se_cmpeqss)={ (a.sf[0] == b.sf[0])*0xffffffff, a.sf[1], a.sf[2], a.sf[3] }
戻値(se_cmpltss)={ (a.sf[0] < b.sf[0])*0xffffffff, a.sf[1], a.sf[2],
a.sf[3] }
戻値(se_cmpless)={ (a.sf[0] <= b.sf[0])*0xffffffff, a.sf[1], a.sf[2],
a.sf[3] }
戻値(se_cmpneqss)={ (a.sf[0] != b.sf[0])*0xffffffff, a.sf[1], a.sf[2], a.sf[3] }
戻値(se_cmpnltss)={ (!(a.sf[0] < b.sf[0]))*0xffffffff, a.sf[1],
a.sf[2], a.sf[3] }
戻値(se_cmpnless)={ (!(a.sf[0] <= b.sf[0]))*0xffffffff, a.sf[1],
a.sf[2], a.sf[3] }
戻値(se_cmpordss)={ (a.sf[0] != NaN && b.sf[0] != NaN)*0xffffffff,
a.sf[1], a.sf[2], a.sf[3] }
戻値(se_cmpnordss)={ (a.sf[0] == NaN || b.sf[0] == NaN)*0xffffffff, a.sf[1], a.sf[2], a.sf[3] }
7.7 並列比較
xmm_t se_cmpeqps(xmm_t a, xmm_t b);
xmm_t se_cmpltps(xmm_t a, xmm_t b);
xmm_t se_cmpleps(xmm_t a, xmm_t b);
xmm_t se_cmpneqps(xmm_t a, xmm_t b);
xmm_t se_cmpnltps(xmm_t a, xmm_t b);
xmm_t se_cmpnleps(xmm_t a, xmm_t b);
xmm_t se_cmpordps(xmm_t a, xmm_t b);
xmm_t se_cmpunordps(xmm_t a, xmm_t b);
機能:v4sf型の引数aとbの各対応float値同士の比較(等しい,小なり,以下,
等しくない,小なりでない,以下でない,順序付け可能,順序付け不能).
比較結果が“真”の場合,対応する32ビットがすべて1に,さもなければ0に
セットされます.
戻値(se_cmpeqps)={ (a.sf[0] == b.sf[0])*0xffffffff, ..., (a.sf[3] == b.sf[3])*0xffffffff }
戻値(se_cmpltps)={ (a.sf[0] < b.sf[0])*0xffffffff, ..., (a.sf[3]
< b.sf[3])*0xffffffff }
戻値(se_cmpleps)={ (a.sf[0] <= b.sf[0])*0xffffffff, ..., (a.sf[3]
<= b.sf[3])*0xffffffff }
戻値(se_cmpneqps)={ (a.sf[0] != b.sf[0])*0xffffffff, ..., (a.sf[3] != b.sf[3])*0xffffffff }
戻値(se_cmpnltps)={ (!(a.sf[0] < b.sf[0]))*0xffffffff, ..., !(a.sf[3]
< b.sf[3])*0xffffffff }
戻値(se_cmpnleps)={ (!(a.sf[0] <= b.sf[0])}*0xffffffff, ..., !(a.sf[3]
<= b.sf[3])*0xffffffff }
戻値(se_cmpordps)={ (a.sf[0] != NaN && b.sf[0] != NaN)*0xffffffff,
..., (a.sf[3] != NaN && b.sf[3] != NaN)*0xffffffff }
戻値(se_cmpnordps)={ (a.sf[0] == NaN || b.sf[0] == NaN)*0xffffffff, ..., (a.sf[3] == NaN || b.sf[3] == NaN)*0xffffffff }
7.8 順序ありスカラー比較(戻り値は論理値)
int se_comieqss(xmm_t a, xmm_t b);
int se_comiltss(xmm_t a, xmm_t b);
int se_comiless(xmm_t a, xmm_t b);
int se_comigtss(xmm_t a, xmm_t b);
int se_comigess(xmm_t a, xmm_t b);
int se_comineqss(xmm_t a, xmm_t b);
機能:v4sf型の引数aとbの最下位のfloat値の比較(等しい,小なり,以下,大なり,
以上,等しくない).比較結果が“真”の場合,1を返し,“偽”の場合,0を返します.
a.sf[0]或いはb.sf[0]のどれかがNaNであれば,不法操作違反が発生します.
7.9 順序なしスカラー比較(戻り値は論理値)
int se_ucomieqss(xmm_t a, xmm_t b);
int se_ucomiltss(xmm_t a, xmm_t b);
int se_ucomiless(xmm_t a, xmm_t b);
int se_ucomigtss(xmm_t a, xmm_t b);
int se_ucomigess(xmm_t a, xmm_t b);
int se_ucomineqss(xmm_t a, xmm_t b);
機能:se_comieqss, se_comiltss, se_comiless, se_comigtss, se_comigess, se_comineqssとほぼ同じ
ですが,a.sf[0]或いはb.sf[0]のどれかがSNaNであれば,不法操作違反が発生します.
7.10 型変換
int se_cvtss2si(xmm_t a);
機能:v4sf型の引数aの最下位のfloat値を(CPUの既定ラウンドモードで)int型に変換します.
戻値=rint(a.sf[0])
mm_t se_cvtps2pi(xmm_t a);
機能:v4sf型引数aの下位2個のfloat値を(CPUの既定ラウンドモードで)int型に変換し,
v2si型で返します.
戻値=(mm_t){ rint(a.sf[0]), rint(a.sf[1]) }
int se_cvttss2si(xmm_t a);
機能:v4sf型引数aの最下位のfloat値を(切り捨てモードで)int型に変換します.
戻値=(int)a.sf[0]
mm_t se_cvttps2pi(xmm_t a);
機能:v4sf型引数aの下位2個のfloat値を(切り捨てモードで)int型に変換し,
v2si型で返します.
戻値=(mm_t){ (int)a.sf[0], (int)a.sf[1] }
xmm_t se_cvtsi2ss(xmm_t a, int b);
機能:int型引数aをfloat型に変換し,v4sf型の引数aの最下位のfloat値に代入して返します.
戻値={ (float)b, a.sf[1], a.sf[2], a.sf[3] }
xmm_t se_cvtpi2ps(xmm_t a, mm_t b);
機能:v2si型引数bにある2個のint値をfloat値に変換して,v4sf型の引数aの下位2個のfloatに
代入して返します.
戻値={ (float)b.si[0], (float)b.si[1], a.sf[2], a.sf[3] }
xmm_t se_cvt_v4hi_to_ps(mm_t a);
機能:v4hi型引数aにある4個のshort値をfloat値に変換して,v4sf型で返します.
戻値={ (float)a.hi[0], ..., (float)a.hi[3] }
xmm_t se_cvt_uv4hi_to_ps(mm_t a);
機能:v4hi型引数aにある4個のunsigned short値をfloat値に変換して,v4sf型で返します.
戻値={ (float)a.uhi[0], ..., (float)a.uhi[3] }
xmm_t se_cvt_lv8qi_to_ps(mm_t a);
機能:v8qi型引数aにある下位4個のsigned char値をfloat値に変換して,v4sf型で返します.
戻値={ (float)a.qi[0], ..., (float)a.qi[3] }
xmm_t se_cvt_luv8qi_to_ps(mm_t a);
機能:v8qi型引数aにある下位4個のunsigned char値をfloat値に変換して,v4sf型で返します.
戻値={ (float)a.uqi[0], ..., (float)a.uqi[3] }
xmm_t se_cvt_2v2si_to_ps(mm_t a, mm_t b);
機能:v2si型引数aとbにある4個のint値をfloat値に変換して,v4sf型で返します.
戻値={ (float)a.si[0], (float)a.si[1], (float)b.si[0], (float)b.si[1] }
mm_t se_cvt_ps_to_v4hi(xmm_t a);
機能:v4sf型引数aにある4個のfloat値をshort値に変換して,v4hi型で返します.
戻値={ (short)a.sf[0], ..., (short)a.sf[3] }
mm_t se_cvt_ps_to_v8qi(xmm_t a);
機能:v4sf型引数aにある4個のfloat値をsigned char値に変換して,v8qi型の下位4個に設定して返します.
戻値={ (signed char)a.sf[0], ..., (signed char)a.sf[3], 0, 0, 0, 0 }
7.11 組み換え
xmm_t se_shufps(xmm_t a, xmm_t b, int msk);
機能:定数int型mskによりaとbの要素を組み替えします.
戻値={ a.sf[msk & 0x3], a.sf[(msk >> 2)&0x3], b.sf[(msk
>> 4)&0x3], b.sf[(msk >> 6)&0x3] }
xmm_t se_shufps_n3210(xmm_t a, xmm_t b, int ns3, int n2, int n1, int n0);
機能:定数int型n0, n1, n2, n3によりaとbの要素を組み替えします.
戻値={ a.sf[n0], a.sf[n1], b.sf[n2], b.sf[n3] }
7.12 アンパック
xmm_t se_unpckhps(xmm_t a, xmm_t b);
機能:上位アンパック
戻値={ a.sf[2], b.sf[2], a.sf[3], b.sf[3] }
xmm_t se_unpcklps(xmm_t a, xmm_t b);
機能:下位アンパック
戻値={ a.sf[0], b.sf[0], a.sf[1], b.sf[1] }
7.13 データの移動
xmm_t se_movhps_m2r(xmm_t a, mm_t const *ptr);
機能:*ptrにある64ビットデータをaの上位64ビットにコピーして返します.
戻り値={ a.sf[0], a.sf[1], *(float *)ptr, *((float)ptr + 1) }
void se_movhps_r2m(mm_t *ptr, xmm_t a);
機能:aの上位64ビットを*ptrにコピーします.
*(float *)ptr = a.sf[2];
*((float)ptr + 1) = a.sf[3];
xmm_t se_movhlps(xmm_t a, xmm_t b);
機能:bの上位64ビットデータをaの下位64ビットにコピーして返します.
戻り値={ b.sf[2], b.sf[3], a.sf[2], a.sf[3] }
xmm_t se_movlhps(xmm_t a, xmm_t b);
機能:bの下位64ビットデータをaの上位64ビットにコピーして返します.
戻り値={ a.sf[0], a.sf[1], b.sf[0], b.sf[1] }
xmm_t se_movlps_m2r(xmm_t a, mm_t const *ptr);
機能:*ptrにある64ビットデータをaの下位64ビットにコピーして返します.
戻り値={ *(float *)ptr, *((float)ptr + 1), a.sf[2], a.sf[3] }
void se_movlps_r2m(mm_t *ptr, xmm_t a);
機能:aの下位64ビットを*ptrにコピーします.
*(float *)ptr = a.sf[0];
*((float)ptr + 1) = a.sf[1];
int se_movmskps(xmm_t a);
機能:aにある4個のfloatの最上位(符号ビット)を取り,4ビットマスクを構成して返します.
戻値=(a.sf[0]の符号ビット) | (((a.sf[1]の符号ビット)<<1) |
(((a.sf[2]の符号ビット)<<2) | (((a.sf[3]の符号ビット)<<3)
xmm_t se_movss_m2r(float const *p);
機能:*pをv4sf型に変換します.
戻値={ *p, 0.0, 0.0, 0.0 }
xmm_t se_movaps_m2r(float const *p);
機能:*pから4個floatをロードし,v4sf型にして返します.pは16の倍数でなければなりません.
戻値={ p[0], p[1], p[2], p[3] }
xmm_t se_movups_m2r(float const *p);
機能:*pから4個floatをロードし,v4sf型にして返します.pは16の倍数でなくてもよい.
戻値={ p[0], p[1], p[2], p[3] }
xmm_t se_setzerops(void);
機能:v4sf型の0値を返します.
戻値={ 0.0, 0.0, 0.0, 0.0 }
void se_movss_r2m(float *p, xmm_t a);
機能:aの下位float 値を*pにコピーします.
void se_movaps_r2m(float *p, xmm_t a);
機能:aにある4個のfloat 値を*pにコピーします.pは16の倍数でなければなりません.
*(v4sf *)p = a;
void se_movups_r2m(float *p, xmm_t a);
機能:aにある4個のfloat 値を*pにコピーします.pは16の倍数でなければなりません.
*(v4sf *)p = a;
xmm_t se_movss_r2r(xmm_t a, xmm_t b);
機能:bの下位float値をaの下位floatにコピーして返します.
戻値={ b.sf[0], a.sf[1], a.sf[2], a.sf[3] }
7.14 コントロールレジスタの操作
MXCSRレジスタには32ビットがあります.上位16ビットが予約済みで,現在はすべて0です.0以外の値をセットしようとすると,一般違反が起こります.その他のビットは下記のとおりです.
15 bit: FLUSH-TO-ZEROフラグ.このを1にセットすると,桁落ちが起きたとき,結果が0になります.
精度が落ちるが,速度が速くなります.
14-13bit: 丸めモード.[00]: 至近値に丸める.[01]: マイナス無限大に近い方に丸める.
[10]:プラス無限大に丸める.[11]:切捨ててゼロにする.
12bit: 精度違反マスク.1にセットすると,計算結果に精度落ちが生じても,精度例外は報告されません.
11bit: 桁落ち違反マスク.1にセットすると,計算結果に桁落ちが生じても,桁落ち例外は報告されません.
10bit: 桁溢れ違反マスク.1にセットすると,計算結果に桁溢れが生じても,桁溢れ例外は報告されません.
9bit: ゼロによる除算違反マスク.1にセットすると,ゼロで割り算しても,ゼロによる除算例外は報告されません.
8bit: 非正規数違反マスク.1にセットすると,計算結果が非正規数であっても,非正規数違反は報告されません.
7bit: 不法操作違反マスク.1にセットすると,不法操作を行っても,不法操作例外は報告されません.
6bit: 非正規数は0と見なすモード.1にセットすると,非正規数は0に変換されます.この機能はPentium4以降のCPUがサポートされ,それ以前のCPUでこのビットを1にセットしようとすると,一般違反が起きます.
5bit: 精度違反.精度違反が起きたとき,1にセットされます.
4bit: 桁落ち違反.桁落ちが発生したとき,1にせっとされます.
3bit: 桁あふれ違反.桁溢れが発生したとき,1にセットされます.
2bit: ゼロによる除算違反.ゼロで除算したとき,1にセットされます.
1bit: 非正規数違反.計算結果が非正規数になったとき,1にセットされます>.
0bit: 不法操作違反.不法操作をしたとき,1にセットされます.
unsigned int se_stmxcsr(void);
機能:制御レジスタの内容を読み出します.
unsigned int se_get_exception_state(void);
機能:違反状態(0〜5ビット)を読み出します.
unsigned int se_get_exception_mask(void);
機能:違反マスク(7〜12ビット)を読み出します.
unsigned int se_get_rounding_mode(void);
機能:丸めモードを読み出します.
unsigned int se_get_flush_zero_mode(void);
機能:FLUSH-TO-ZEROビットを呼び出します.
void se_ldmxcsr(unsigned int t);
機能:制御レジスタの内容をtにセットします.
void se_set_exception_state(unsigned int __mask);
機能:違反状態をセットします.
void se_set_exception_mask(unsigned int __mask);
機能:違反マスクをセットします.
void se_set_rounding_mode(unsigned int __mode);
機能:丸めモードをセットします.
void se_set_flush_zero_mode(unsigned int __mode);
機能:FLUSH-TO-ZEROビットをセットします.
7.15 SSE拡張MMX機能
7.15.1 16ビットデータのの取り出し
unsigned int se_pextrw(mm_t a, int n);
機能:aからnで指定したshort値の取り出し.nはint型定数でなければいけません.
戻値=a.uhi[n&0x3]
7.15.2 16ビットデータの挿入
mm_t se_pinsrw(mm_t a, int d, int n);
機能:dをaのnで指定したshort値にコピーして,aを返します.
戻値=(a.uhi[n&0x3]=d, a)
7.15.3 最大/最小値
mm_t se_pmaxsw(mm_t a, mm_t b);
機能:並列最大short値.
戻値={ MAX(a.hi[0], b.hi[0]), ..., MAX(a.hi[3], b.hi[3]) }
mm_t se_pmaxub(mm_t a, mm_t b);
機能:並列最大unsigned char値.
戻値= { MAX(a.uqi[0], b.uqi[0]), ..., MAX(a.uqi[7], b.uqi[7]) }
mm_t se_pminsw(mm_t a, mm_t b);
機能:並列最小short値.
戻値={ MIN(a.hi[0], b.hi[0]), ..., MIN(a.hi[3], b.hi[3]) }
mm_t se_pminub(mm_t a, mm_t b);
機能:並列最少unsigned char値.
戻値= { MIN(a.uqi[0], b.uqi[0]), ..., MIN(a.uqi[7], b.uqi[7]) }
7.15.4 符号ビットの取り出し
int se_pmovmskb(mm_t a)
機能:aにある8個のsigned char値の最上位(符号ビット)を取り,8ビットマスクを構成して返します.
戻値=(a.qi[0]の符号ビット) | (((a.qi[1]の符号ビット)<<1) | ...
| (((a.qi[7]の符号ビット)<<7)
7.15.5 符号なしshortの掛算
mm_t se_pmulhuw(mm_t a, mm_t b);
機能:並列unsigned short掛け算の結果の上位16ビットを返す.
戻値={ (m1.uhi[0]*m2.uhi[0]) >> 16, ..., (m1.uhi[03]*m2.uhi[3])
>> 16 }
7.15.6 組み換え
mm_t se_pshufw(mm_t a, int n);
機能:v4hi型引数aをnによって組み替えます.
戻値={ a.hi[n&0x3], a.hi[(n>>2)&0x3], a.hi[(n>>4)&0x3],
a.hi[(n>>6)&0x3] }
mm_t se_pshufw_n3210(mm_t a, int n3, int n2, int n1, int n0);
機能:v4hi型引数aをn0, n1, n2, n3によって組み替えます.
戻値={ a.hi[n0], a.hi[n1], a.hi[n2], a.hi[n3] }
7.15.7 マスクによるデータの移動
void se_maskmovq(mm_t a, mm_t n, char *p);
機能:v8qi型の引数nの各signed charの符号ビットが1であれば,対応するv8qi型引数aの
signed char値をpに保存されます.C言語風で説明すると,下記のコードの結果と同じです.
int i; for (i = 0; i < 8; ++i) if (n.qi[i] < 0) p[i] =
a.qi[i];
7.115.8 平均値
mm_t se_pavgb(mm_t a, mm_t b);
機能:v8qi型の符号なし平均.
戻値={ (a.uqi[0]+b.uqi[0])/2, ..., (a.uqi[7]+b.uqi[7])/2 }
mm_t se_pavgw(mm_t a, mm_t b);
機能:v4hi型の符号なし平均.
戻値= { (a.uhi[0]+b.uhi[0])/2, ..., (a.uhi[3]+b.uhi[3])/2 }
7.15.9 差の絶対値の合計
mm_t se_psadbw(mm_t a, mm_t b);
機能:v8qi型の符号なし差の絶対値の合計.
戻値=(v4hi){ |a.uqi[0]-b.uqi[0]|+,...,+|a.uqi[7]-b.uqi[7]|, 0, 0, 0 }
7.16 非一時保存
void se_movntq(mm_t *p, mm_t a);
機能:キャッシュレス保存.*p = a;
void se_movntps(float *p, xmm_t a);
機能:キャッシュレス保存.*(xmm_t *)p = a;
7.17 セーブ保存柵
void se_sfence(void);
機能:この関数より前に保存したデータがすべて“見える”状態にする.
7.18 4x4行列の転置
se_transpos_4x4(xmm_t row0, xmm_t row1, xmm_t row2, xmm_t row3);
機能:4x4のfloat要素の行列の転置.Se_transpos_4x4はマクロであり,4個の
引数row0, ..., row3は,行列の各行です.処理したあと,4個の引数には
転置した行列の各行が入っています.
8 SSE2拡張機能
SSE2拡張機能はPentium4以降のX86系CPUに搭載されていて,それより旧式のCPU(i386,
i486, Pentium, PentiumPro, Pentium-MMX, PeniumII, PentiumIIIなど)では利用できません.SSE2拡張機能主に倍精度の浮動小数点データの並列演算をサポートします.そして,ほとんどのMMX機能は128ビットバージョンに拡張されています.使用するベクトル型はMMX,SSE拡張機能がサポートするものの他に,v2dfが追加されます.
8.1 スカラー四則演算
xmm_t se2_addsd(xmm_t a, xmm_t b);
xmm_t se2_subsd(xmm_t a, xmm_t b);
xmm_t se2_mulsd(xmm_t a, xmm_t b);
xmm_t se2_divsd(xmm_t a, xmm_t b);
機能:v2df型の引数aとbの下位のdouble値同士の四則演算.
戻値={ a.df[0] 演算子 b.df[0], a.df[1] }
8.2 その他のスカラー演算
xmm_t se2_sqrtsd(v2df a);
機能:v2df型の引数の下位のdouble値の平方根.
戻値={ sqrt(a.df[0]), a.df[1] }
xmm_t se2_minsd(xmm_t a, xmm_t b);
xmm_t se2_maxsd(xmm_t a, xmm_t b);
機能:v2df型の引数aとbの下位のdouble値の中の最小値/最大値.
戻値={ 最小/最大(a.df[0], b.df[0]), a.df[1] }
8.3 並列四則演算
xmm_t se2_addpd(xmm_t a, xmm_t b);
xmm_t se2_subpd(xmm_t a, xmm_t b);
xmm_t se2_mulpd(xmm_t a, xmm_t b);
xmm_t se2_divpd(xmm_t a, xmm_t b);
機能:引数aとbの2個のdouble値同士の並列四則演算
戻値={ a.df[0] 演算子 b.df[0], a.df[1] 演算子 b.df[1] }
8.4 その他の並列演算
xmm_t se2_sqrtpd(xmm_t a);
機能:並列平方根
戻値={ sqrt(a.df[0]), sqrt(a.df[1]) }
xmm_t se2_minpd(xmm_t a, xmm_t b);
xmm_t se2_maxpd(xmm_t a, xmm_t b);
機能:並列最小値/最大値.
戻値={ 最小/最大(a.df[0], b.df[0]), 最小/最大(a.df[1], b.df[1])
}
8.5 ビットごと論理演算
xmm_t se2_andpd(xmm_t a, xmm_t b);
xmm_t se2_andnpd(xmm_t a, xmm_t b);
xmm_t se2_orpd(xmm_t a, xmm_t b);
xmm_t se2_xorpd(xmm_t a, xmm_t b);
機能:ビットごと論理積,否定論理積,論理和,排他的論理和
戻値(se2_andpd)={ a.di[0] & b.di[0], a.di[1] & b.di[1] }
戻値(se2_andnpd)={ ~a.di[0] & b.di[0], ~a.di[1] & b.di[1]
}
戻値(se2_orpd)={ a.di[0] | b.di[0], a.di[1] | b.di[1] }
戻値(se2_xorpd)={ a.di[0] ^ b.di[0], a.di[1] ^ b.di[1] }
8.6 スカラー比較1(戻り値はビットマスク)
xmm_t se2_cmpeqsd(xmm_t a, xmm_t b);
xmm_t se2_cmpltsd(xmm_t a, xmm_t b);
xmm_t se2_cmplesd(xmm_t a, xmm_t b);
xmm_t se2_cmpneqsd(xmm_t a, xmm_t b);
xmm_t se2_cmpnltsd(xmm_t a, xmm_t b);
xmm_t se2_cmpnlesd(xmm_t a, xmm_t b);
xmm_t se2_cmpordsd(xmm_t a, xmm_t b);
xmm_t se2_cmpunordsd(xmm_t a, xmm_t b);
機能:v2df型の引数aとbの下位のdouble値の比較(等しい,小なり,以下,
等しくない,小なりでない,以下でない,順序付け可能,順序付け不能).
比較結果が“真”の場合,下位64ビットがすべて1に,さもなければ0に
セットされます.
戻値(se2_cmpeqsd)={ (a.df[0] == b.df[0])*0xffffffffffffffff, a.df[1]
}
戻値(se2_cmpltsd)={ (a.df[0] < b.df[0])*0xffffffffffffffff, a.df[1]
}
戻値(se2_cmplesd)={ (a.df[0] <= b.df[0])*0xffffffffffffffff, a.df[1]
}
戻値(se2_cmpneqsd)={ (a.df[0] != b.df[0])*0xffffffffffffffff, a.df[1] }
戻値(se2_cmpnltsd)={ (!(a.df[0] < b.df[0]))*0xffffffffffffffff,
a.df[1] }
戻値(se2_cmpnlesd)={ (!(a.df[0] <= b.df[0]))*0xffffffffffffffff,
a.df[1] }
戻値(se2_cmpordsd)={ (a.df[0] != NaN && b.sf[0] != NaN)*0xffffffffffffffff, a.df[1] }
戻値(se2_cmpnordsd)={ (a.df[0] == NaN || b.sf[0] == NaN)*0xffffffffffffffff,
a.df[1] }
8.7 並列比較
xmm_t se2_cmpeqpd(xmm_t a, xmm_t b);
xmm_t se2_cmpltpd(xmm_t a, xmm_t b);
xmm_t se2_cmplepd(xmm_t a, xmm_t b);
xmm_t se2_cmpneqpd(xmm_t a, xmm_t b);
xmm_t se2_cmpnltpd(xmm_t a, xmm_t b);
xmm_t se2_cmpnlepd(xmm_t a, xmm_t b);
xmm_t se2_cmpordpd(xmm_t a, xmm_t b);
xmm_t se2_cmpunordpd(xmm_t a, xmm_t b);
機能:v2df型の引数aとbの各対応double値同士の比較(等しい,小なり,以下,
等しくない,小なりでない,以下でない,順序付け可能,順序付け不能).
比較結果が“真”の場合,対応する64ビットがすべて1に,さもなければ0に
セットされます.
戻値(se2_cmpeqpd)={ (a.df[0] == b.df[0])*0xffffffffffffffff, a.df[1]
== b.df[1])*0xfffffffffffffff }
戻値(se2_cmpltpd)={ (a.df[0] < b.df[0])*0xffffffffffffffff, (a.df[1]
< b.df[1])*0xffffffffffffffff }
戻値(se2_cmplepd)={ (a.df[0] <= b.df[0])*0xffffffffffffffff, (a.df[1] <= b.df[1])*0xffffffffffffffff }
戻値(se2_cmpneqpd)={ (a.df[0] != b.df[0])*0xffffffffffffffff, (a.df[1]
!= b.df[1])*0xffffffffffffffff }
戻値(se2_cmpnltpd)={ (!(a.df[0] < b.df[0]))*0xffffffffffffffff,
!(a.df[1] < b.df[1])*0xffffffffffffffff }
戻値(se2_cmpnlepd)={ (!(a.df[0] <= b.df[0])}*0xffffffffffffffff, !(a.df[1] <= b.df[1])*0xffffffffffffffff }
戻値(se2_cmpordpd)={ (a.df[0] != NaN && b.df[0] != NaN)*0xffffffffffffffff,
(a.df[1] != NaN && b.df[1] != NaN)*0xffffffffffffffff }
戻値(se2_cmpnordpd)={ (a.df[0] == NaN || b.df[0] == NaN)*0xffffffffffffffff,
(a.df[1] == NaN || b.df[1] == NaN)*0xffffffffffffffff }
8.8 順序ありスカラー比較(戻り値は論理値)
int se2_comieqsd(xmm_t a, xmm_t b);
int se2_comiltsd(xmm_t a, xmm_t b);
int se2_comilesd(xmm_t a, xmm_t b);
int se2_comigtsd(xmm_t a, xmm_t b);
int se2_comigesd(xmm_t a, xmm_t b);
int se2_comineqsd(xmm_t a, xmm_t b);
機能:v2df型の引数aとbの下位のdouble値の比較(等しい,小なり,以下,大なり,
以上,等しくない).比較結果が“真”の場合,1を返し,“偽”の場合,0を返します.
a.df[0]或いはb.df[0]のどれかがNaNであれば,不法操作違反が発生します.
8.9 順序なしスカラー比較(戻り値は論理値)
int se2_ucomieqsd(xmm_t a, xmm_t b);
int se2_ucomiltsd(xmm_t a, xmm_t b);
int se2_ucomilesd(xmm_t a, xmm_t b);
int se2_ucomigtsd(xmm_t a, xmm_t b);
int se2_ucomigesd(xmm_t a, xmm_t b);
int se2_ucomineqsd(xmm_t a, xmm_t b);
機能:se2_comieqsd, se2_comiltsd, se2_comilesd, se2_comigtsd, se2_comigesd, se2_comineqssとほぼ同じ
ですが,a.df[0]或いはb.df[0]のどれかがSNaNであれば,不法操作違反が発生します.
8.10 型変換
xmm_t se2_cvtdq2pd(xmm_t a);
機能:v4si型引数aにある下位2個のint値をdouble値に変換して返します.
戻値={ (double)a.si[0], (double)a.si[1] }
xmm_t se2_cvtdq2ps(xmm_t a);
機能:v4si型引数aにある4個のint値をfloat値に変換して返します.
戻値={ (float)a.si[0], ..., (float)a.si[3] }
xmm_t se2_cvtpd2dq(xmm_t a);
機能:v2df型引数aにある2個のdouble値をint値に変換して返します.
戻値={ rint(a.df[0]), rint(a.df[1]), 0, 0 }
mm_t se2_cvtpd2pi(xmm_t a);
機能:v2df型引数aにある2個のdouble値をint値に変換して返します.
戻値={ rint(a.df[0]), rint(a.df[1]) }
xmm_t se2_cvtpd2ps(xmm_t a);
機能:v2df型引数aにある2個のdouble値をfloat値に変換して返します.
戻値={ (float)a.df[0], (float)a.df[1], 0.0f, 0.0f }
xmm_t se2_cvttpd2dq(xmm_t a);
機能:v2df型引数aにある2個のdouble値をint値に変換して返します.
戻値=(v4si){ (int)a.df[0], (int)a.df[1], 0, 0 }
mm_t se2_cvttpd2pi(xmm_t a);
機能:v2df型引数aにある2個のdouble値をint値に変換して返します.
戻値=(v2si){ (int)a.df[0], (int)a.df[1] }
xmm_t se2_cvtpi2pd(mm_t a);
機能:v2si型引数aにある2個intの値をdouble値に変換して返します.
戻値=(v2di){ (double)a.si[0], (double)a.si[1] }
xmm_t se2_cvtps2dq(xmm_t a);
機能:v4sf型引数aにある4個floatの値をint値に変換して返します.
戻値=(v4si){ rint(a.sf[0]), rint(a.sf[1]), rint(a.sf[2]), rint(a.sf[3])
}
xmm_t se2_cvttps2dq(xmm_t a);
機能:v4sf型引数aにある4個floatの値をint値に変換して返します.
戻値=(v4si){ (int)a.sf[0], (int)a.sf[1], (int)a.sf[2], (int)a.sf[3]
}
xmm_t se2_cvtps2pd(xmm_t a);
機能:v4sf型引数aにある2個floatの値をdouble値に変換して返します.
戻値=(v2df){ (double)a.sf[0], (double)a.sf[1] }
int se2_cvtsd2si(xmm_t a);
機能:v2df型引数aにある下位のdouble値をint値に変換して返します.
戻値= rint(a.df[0])
int se2_cvttsd_si32(xmm_t a);
機能:v2df型引数aにある下位のdouble値をint値に変換して返します.
戻値=(int)a.df[0]
xmm_t se2_cvtsd2ss(xmm_t a, xmm_t b);
機能:v2df型引数aにある下位のdouble値をfloat値に変換してaの下位にコピーして返します.
戻値={ (float)b.df[0], a.sf[1], a.sf[2], a.sf[3] }
xmm_t se2_cvtsi2sd(xmm_t a, int b);
機能:bをdoubleに変換してv2df型引数aにある下位のdouble値にaの下位にコピーして返します.
戻値={ (double)b, a.df[1] }
xmm_t se2_cvtss2sd(xmm_t a, xmm_t b);
機能:bの下位float値をdoubleに変換してv2df型引数aにある下位のdouble値にaの下位にコピーして返します.
戻値={ (double)b.sf[0], a.df[1] }
8.11 組み換え
xmm_t se2_shufpd(xmm_t a, xmm_t b, int msk);
機能:定数int型mskによりaとbの要素を組み替えします.
戻値={ a.df[msk & 0x3], b.df[(msk >> 4)&0x3] }
xmm_t se2_shufpd_n10(xmm_t a, xmm_t b, int n1, int n0);
機能:定数int型n0, n1によりaとbの要素を組み替えします.
戻値={ a.df[n0], b.df[n2] }
8.12 アンパック
xmm_t se2_unpckhpd(xmm_t a, xmm_t b);
機能:上位アンパック
戻値={ a.df[1], b.df[1] }
xmm_t se2_unpcklpd(xmm_t a, xmm_t b);
機能:下位アンパック
戻値={ a.df[0], b.df[0] }
8.13 データの移動
xmm_t se2_movsd_m2r(double const *p);
機能:*pから1個doubleをロードし,v2df型にして返します.
戻値={ *p, 0.0 }
xmm_t se2_movapd_m2r(double const *p);
機能:*pから2個doubleをロードし,v2df型にして返します.pは16の倍数でなければなりません.
戻値={ p[0], p[1] }
xmm_t se2_movupd_m2r(double const *p);
機能:*pから2個doubleをロードし,v2df型にして返します.pは16の倍数である必要はありません.
戻値={ p[0], p[1] }
xmm_t se2_setzeropd(void);
機能:v2df型の0を返します.
戻値={ 0.0, 0.0 }
void se2_movsd_r2m(double *p, xmm_t a);
機能:aの下位double値を*pにコピーします.
*p = a.df[0];
void se2_movapd_r2m(double *p, xmm_t a);
機能:aを*pにコピーします.pは16の倍数でなければいけません.
p[0] = a.df[0], p[1] = a.df[1]
void se2_movupd_r2m(double *p, xmm_t a);
機能:aを*pにコピーします.pは16の倍数である必要はありません.
p[0] = a.df[0], p[1] = a.df[1]
xmm_t se2_movsd_r2r(xmm_t a, xmm_t b);
機能:bの下位doubleをaの下位doubleにコピーして返します.
戻値={ b.df[0], a.df[1] }
xmm_t se2_movhpd_m2r(xmm_t a, double const *b);
機能:*bをaの上位doubleにコピーして返します.
戻値={ a.df[0], *b }
void se2_movhpd_r2m(double *a, v2df b);
機能:bの上位doubleを*aにコピーします.
*a = b.df[1];
xmm_t se2_movlpd_m2r(xmm_t a, double const *b);
機能:*bをaの下位doubleにコピーして返します.
戻値={ *b, a.df[1] }
void se2_movlpd_r2m(double *a, xmm_t b);
機能:bの下位doubleを*aにコピーします.
*b = a.df[0];
int se2_movemskpd(xmm_t a);
機能:aの2個のdoubleの符号ビットを返します.
戻値=(a.df[0] >= 0) | ((a.df[1] >= 0) << 1)
xmm_t se2_movdqa_m2r(xmm_t const *p);
機能:xmm_t型変数をロードします.pは16の倍数でなければいけません.
戻値=*(xmm_t *)p
xmm_t se2_movdqu_m2r(xmm_t const *p);
機能:xmm_t型変数をロードします. pは16の倍数である必要はありません.
戻値=*(xmm_t *)p
xmm_t se2_movq_m2r(mm_t const *p);
機能:64ビット値をロードします.
戻値= { *p, 0 }
void se2_movdqa_r2m(xmm_t *p, xmm_t b);
機能:xmm_t型変数bをpにセーブします. pは16の倍数でなければなりません.
*p = b
void se2_movdqu_r2m(xmm_t *p, xmm_t b);
機能:xmm_t型変数bをpにセーブします. pは16の倍数である必要はありません.
*p = b
void se2_movq_r2m(mm_t *p, xmm_t b);
機能:下位64ビットを保存します.
*p = b.di[0];
mm_t se2_movdq2q(xmm_t a);
機能:下位64ビットを返します.
戻値= b.di[0];
xmm_t se2_movq_r2r(xmm_t a);
機能:下位64ビットを移動します.
戻値={ a.di[0], 0 }
xmm_t se2_movd_m2r(int *p);
機能:整数をロードし,v4siの下位にセットして返します.
戻値=(v4si){ *p, 0, 0, 0 }
void se2_movd_r2m(int *p, xmm_t a);
機能:下位32ビットを保存します.*p = a.si[0];
8.14 SSE2拡張MMX機能
8.14.2 アンパック処理
xmm_t se2_unpckhbw128(xmm_t a, xmm_t b);
機能:aの上位8個charを下位とし,bの上位8個charを上位とする8個のshortへの変換,
mm_punpckhbw()の128ビット版.
戻値={ {a.qi[8],b.qi[8]}, ..., {a.qi[15],b.qi[15]} }
xmm_t se2_unpckhwd128(xmm_t a, xmm_t b);
機能:aの上位4個shortを下位とし,bの上位4個shortを上位とする4個のintへの変換. mm_punpckhwd()の128ビット版.
戻値={ {a.hi[4],b.hi[4]}, ..., {a.hi[7],b.hi[7]} }
xmm_t se2_unpckhdq128(xmm_t a, xmm_t b);
機能:aの上位2個のintを下位とし,bの上位2個のintを上位とするlong longへの変換.
mm_punpckhdq()の128ビット版.
戻値={ {a.si[2],b.si[2]}, ..., {a.si[3],b.si[3]} }
xmm_t se2_unpckhqdq128(xmm_t a, xmm_t b);
機能:aの上位long longを下位とし,bの上位long longを上位とする128ビット整数への変換.
戻値={ {a.di[1],b.di[1]} }
xmm_t se2_unpcklbw128(xmm_t a, xmm_t b);
機能:aの下位8個のcharを下位とし,bの下位8個のcharを上位とする8個のshortへの変換.mm_punpcklbw()の128ビット版.
戻値={ {a.qi[0],b.qi[0]}, ..., {a.qi[7],b.qi[7]} }
xmm_t se2_unpcklwd128(xmm_t a, xmm_t);
機能:aの下位4個shortを下位とし,bの下位4個shortを上位とする4個のintへの変換.mm_punpcklwd()の128ビット版.
戻値={ {a.hi[0],b.hi[0]}, ..., {a.hi[3],b.hi[3]} }
xmm_t se2_unpckldq128(xmm_t a, xmm_t b);
機能:aの下位2個のintを下位とし,bの下位2個のintを上位とする2個のlong
longへの変換.mm_punpckldq()の128ビット版.
戻値={ {a.si[0],b.si[0]}, ..., {a.si[1],b.si[1]} }
xmm_t se2_unpcklqdq128(xmm_t a, xmm_t b);
機能:aの下位long longを下位とし,bの下位long longを上位とする128ビット整数への変換.
戻値={ {a.di[0],b.di[1]} }
8.14.3 並列四則演算
xmm_t se2_paddb128(xmm_t a, xmm_t b);
機能:並列v16qi型(signed char, unsigned char両方)の足し算,mm_paddb()の128ビット版.
戻値=(v16qi)a + (v16qi)b
xmm_t se2_paddw128(xmm_t a, xmm_t b);
機能:並列v8hi型(short, unsigned short両方)の足し算,mm_paddw()の128ビット版.
戻値=(v8hi)a + (v8hi)b
xmm_t se2_paddd128(xmm_t a, xmm_t b);
機能:並列v4si型(int, unsigned int両方)の足し算,mm_paddd()の128ビット版.
戻値=(v4si)a + (v4si)b
xmm_t se2_paddq128(xmm_t a, xmm_t b);
機能:並列v2di型(long long, unsigned long long両方)の足し算,mm_paddq()の128ビット版.
戻値=(v2di)a + (v2di)b
xmm_t se2_paddsb128(xmm_t a, xmm_t b);
機能:飽和処理ありsigned charの並列足し算.mm_t mm_paddsb()の128ビット版.
戻値={ a.qi[0]+b.qi[0], ..., a.qi[15]+b.qi[15] }
xmm_t se2_paddsw128(xmm_t a, xmm_t b);
機能:飽和処理ありshortの並列足し算.mm_t mm_paddsw()の128ビット版.
戻値={ a.hi[0]+b.hi[0], ..., a.hi[7]+b.h[7] }
xmm_t se2_paddusb128(xmm_t a, xmm_t b);
機能:飽和処理ありunsigned charの並列足し算.mm_t mm_paddusb()の128ビット版.
戻値={ a.uqi[0]+b.uqi[0], ..., a.uqi[15]+b.uqi[15] }
xmm_t se2_paddusw128(xmm_t a, xmm_t b);
機能:飽和処理ありunsigned shortの並列足し算.mm_t mm_paddusw()の128ビット版.
戻値={ a.uhi[0]+b.uhi[0], ..., a.uhi[15]+b.uhi[15] }
xmm_t se2_psubb128(xmm_t a, xmm_t b);
機能:並列v16qi型(signed char, unsigned char両方)の引き算.mm_psubb()の128ビット版.
戻値=(v16qi)a - (v16qi)b
xmm_t se2_psubw128(xmm_t a, xmm_t b);
機能:並列v8hi型(short, unsigned short両方)ルの引き算.mm_psubw()の128ビット版.
戻値=(v8hi)a - (v8hi)b
xmm_t se2_psubd128(xmm_t a, xmm_t b);
機能:並列v4si型(int, unsigned int両方)の引き算.mm_psubd()の128ビット版.
戻値=(v4si)a - (v4si)b
xmm_t se2_psubq128(xmm_t a, xmm_t b);
機能:並列v2di型(long long, unsigned long long)の引き算.mm_psubq()の128ビット版.
戻値=(v2di)a - (v2di)b
xmm_t se2_psubsb128(xmm_t a, xmm_t b);
機能:飽和処理ありsigned charの並列引き算.mm_psubsb()の128ビット版.
戻値={ a.qi[0]-b.qi[0], ..., a.qi[15]-b.qi[15] }
xmm_t se2_psubsw128(xmm_t a, xmm_t b);
機能:飽和処理ありshortの並列引き算.mm_psubsw()128ビット版.
戻値={ a.hi[0]-b.hi[0], ..., a.hi[7]-b.hi[7] }
xmm_t se2_psubusb128(xmm_t a, xmm_t b);
機能:飽和処理ありunsigned charの並列引き算.mm_psubusb()の128ビット版.
戻値={a.uqi[0]-b.uqi[0], ..., a.uqi[15]-b.uqi[15] }
xmm_t se2_psubusw128(xmm_t a, xmm_t b);
機能:飽和処理ありunsigned shortの並列引き算.mm_psubusw()の128ビット版.
戻値={ a.uhi[0]-b.uhi[0], ..., a.uhi[7]-b.uhi[7] }
xmm_t se2_pmaddwd128(xmm_t a, xmm_t b);
機能:shortの積和の計算.結果は4個のint.mm_pmaddwd()の128ビット版.
戻値={ a.hi[0]*b.hi[0]+a.hi[1]*b.hi[1], a.hi[2]*b.hi[2]+a.hi[3]*b.hi[3],
a.hi[4]*b.hi[4]+a.hi[5]*b.hi[5], a.hi[6]*b.hi[6]+a.hi[7]*b.hi[7] }
xmm_t se2_pmulhw128(xmm_t a, xmm_t b);
機能:shortの並列掛け算.結果の上位16ビットが保存されます.mm_mulhw()の128ビット版.
戻値={(a.hi[0]*b.hi[0])>>16, ..., (a.hi[7]*b.hi[7])>>16 }
xmm_t se2_pmullw128(xmm_t a, xmm_t b);
機能:shortの並列掛け算.結果の下位16ビットが保存されます.mm_mullw()の128ビット版.
戻値={ (a.hi[0]*b.hi[0])&0xffff, ..., (a.hi[7]*b.hi[7])&0xffff }
xmm_t se2_pmulhuw128(xmm_t a, xmm_t b);
機能:並列unsigned short掛け算.結果の上位16ビットが保存されます.se_pmulhuw()の128ビット版.
戻値={ (a.uhi[0]*b.uhi[0]) >> 16, ..., (a.uhi[7]*b.uhi[7]) >> 16 }
mm_t se2_pmuludq(mm_t a, mm_t b);
機能:unsigned int掛け算.結果はunsigned long long.
戻値={ a.usi[0]*b.usi[0] }
xmm_t se2_pmuludq128(xmm_t a, xmm_t b)
機能:並列unsigned int掛け算.結果は2個のunsigned long long.se2_pmuludq()の128ビット版.
戻値={ a.usi[0]*b.usi[0], a.usi[3] * b.usi[3] }
8.14.4 シフト処理
xmm_t se2_psllw128(xmm_t a, xmm_t b);
機能:v8hiベクトルの左シフト.カウンタはxmm_t型.mm_psllw()の128ビット版.
戻値={ a.hi[0] << b, ..., a.hi[7] << b }
xmm_t se2_psllw128_i(xmm_t a, int const b);
機能:v8hiベクトルの左シフト.カウンタはint型定数.mm_psllw_i()の128ビット版.
戻値={ a.hi[0] << b, ..., a.hi[7] << b }
xmm_t se2_pslld128(xmm_t a, xmm_t b);
機能:v4siベクトルの左シフト.カウンタはxmm_t型.mm_pslld()の128ビット版.
戻値={ a.si[0] << b, ..., a.si[3] << b }
xmm_t se2_pslld128_i(xmm_t a, int b);
機能:v4siベクトルの左シフト.カウンタはint型定数.mm_pslld_i()の128ビット版.
戻値={ a.si[0] << b, ..., a.si[3] << n }
xmm_t se2_psllq128(xmm_t a, xmm_t b);
機能:v2diベクトルの左シフト.カウンタはxmm_t型.mm_psllq()の128ビット版.
戻値={ a.di[0] << b, a.di[1] << b }
xmm_t se2_psllq128_i(xmm_t a, int b);
機能:v2diベクトルの左シフト.カウンタはint型定数.mm_psllq_i()の128ビット版.
戻値={ a.di[0] << b, a.di[1] << b }
xmm_t se2_psraw128(xmm_t a, xmm_t b);
機能:v8hiベクトルの右算術シフト.カウンタはxmm_t型.mm_psraw()の128ビット版.
戻値={ a.hi[0] >> b, ..., a.hi[7] >> b }
xmm_t se2_psraw128_i(xmm_t a, int b);
機能:v8hiベクトルの右算術シフト.カウンタはint型定数.mm_psraw_i()の128ビット版.
戻値={ a.hi[0] >> b, ..., a.hi[7] >> b }
xmm_t se2_psrad128(xmm_t a, xmm_t b);
機能:v4siベクトルの右算術シフト.カウンタはxmm_t型.mm_psrad()の128ビット版.
戻値={ a.si[0] >> b, ..., a.si[3] >> b }
xmm_t se2_psrad128_i(xmm_t a, int b);
機能:v4siベクトルの右算術シフト.カウンタはint型定数.mm_psrad_i()の128ビット版.
戻値={ a.si[0] >> b, ..., a.si[3] >> b }
xmm_t se2_psrlw128(xmm_t a, xmm_t b);
機能:v8hiベクトルの右論理シフト.カウンタはxmm_t型.mm_psrlw()の128ビット版.
戻値={ a.uhi[0] >> b, ..., a.uhi[7] >> b }
xmm_t se2_psrlw128_i(xmm_t a, int b);
機能:v8hiベクトルの右論理シフト.カウンタはint型定数. mm_psrlw_i()の128ビット版.
戻値={ a.uhi[0] >> b, ..., a.uhi[7] >> b }
xmm_t se2_psrld128(xmm_t a, xmm_t b);
機能:v4siベクトルの右論理シフト.カウンタはxmm_t型.mm_psrld()の128ビット版.
戻値={ a.usi[0] >> b, ..., a.usi[1] >> b }
xmm_t se2_psrld128_i(xmm_t a, int b);
機能:v4siベクトルの右論理シフト.カウンタはint型定数.mm_psrld_i()の128ビット版.
戻値={ a.usi[0] >> b, ..., a.usi[3]>> b }
xmm_t se2_psrlq128(xmm_t a, xmm_t b);
機能:v2diベクトルの右論理シフト.カウンタはxmm_t型.mm_psrlq()の128ビット版.
戻値={ a.udi[0] >> b, a.udi[1] >> b }
xmm_t se2_psrlq128(xmm_t a, xmm_t b);
機能:v2diベクトルの右論理シフト.カウンタはint型定数.mm_psrlq_i()の128ビット版.
戻値={ a.udi[0] >> b, a.udi[1] >> b }
xmm_t se2_psrldq128_i(xmm_t a, const int b);
機能:128ビット値の右論理バイトシフト.
戻値=a >> (8*b)
xmm_t se2_pslldq128_i(xmm_t a, const int b);
機能:128ビット値の左論理バイトシフト.
戻値=a << (8*b)
8.14.5 ビットごと倫理演算
se2_pand128(xmm_t a, xmm_t b);
機能:ビットごと論理積.mm_pand()の128ビット版.
戻値={ a.di[0] & b.di[0], a.di[1] & b.di[1] }
xmm_t se2_pandn(xmm_t a, xmm_t b);
機能:ビットごと反転論理積.mm_pandn()の128ビット版.
戻値={ ~a.di[0] & b.di[0],~a.di[0] & b.di[0] }
xmm_t se2_por128(xmm_t a, xmm_t b);
機能:ビットごと論理和.mm_por()の128ビット版.
戻値={ a.di[0] | b.di[0], a.di[1] | b.di[1] }
xmm_t se2_pxor128(xmm_t a, xmm_t b);
機能:ビットごと排他論理和.mm_pxor()の128ビット版.
戻値={ a.di[0] ^ b.di[0], a.di[1] ^ b.di[1] }
8.14.6 比較
xmm_t se2_pcmpeqb128(xmm_t a, xmm_t b);
機能:v16qiベクトルの等しさ比較.mm_pcmpeqb()の128ビット版.
戻値={ (a.qi[0]==b.qi[0])*0xff, ..., (a.qi[15]==b.qi[15])*0xff }
xmm_t se2_pcmpgtb128(xmm_t a, xmm_t b);
機能:v16qiベクトルの大なり比較.mm_pcmpgtb()の128ビット版.
戻値={ (a.qi[0]>b.qi[0])*0xff, ..., (a.qi[15]>b.qi[15])*0xff }
xmm_t se2_pcmpeqw128(xmm_t a, xmm_t b);
機能:v8hiベクトルの等しさ比較.mm_pcmpeqw()の128ビット版.
戻値={ (a.hi[0]==b.hi[0])*0xffff, ..., (a.hi[7]==b.hi[7])*0xffff }
xmm_t se2_pcmpgtw128(xmm_t a, xmm_t b);
機能:v8hiベクトルの大なり比較.mm_pcmpgtw()の128ビット版.
戻値={ (a.hi[0]>b.hi[0])*0xffff, ..., (a.hi[7]>b.hi[7])*0xffff
}
xmm_t se2_pcmpeqd128(xmm_t a, xmm_t b);
機能:v4siベクトルの等しさ比較.mm_pcmpeqd()の128ビット版.
戻値={ (a.si[0]==b.si[0])*0xffffffff, ..., (a.si[3]==b.si[3])*0xffffffff }
xmm_t se2_pcmpgtd128(xmm_t a, xmm_t b);
機能:v4siベクトルの大なり比較.mm_pcmpgtd()の128ビット版.
戻値={ (a.si[0]>b.si[0])*0xffffffff, ..., (a.si[3]>b.si[3])*0xffffffff }
8.14.7 0値ベクトル
xmm_t se2_setzero(void);
機能:v2di型の0を返します.
戻値={ 0, 0 }
8.14.8 16 ビットデータの取り出し
unsigned int se2_pextrw128(xmm_t a, int n);
機能:aからnで指定したshort値の取り出し.nはint型定数でなければいけません.se_pextrw()の128ビット版.
戻値=a.uhi[n&0x7]
8.14.9 16ビットデータの挿入
xmm_t se2_pinsrw128(xmm_t a, int d, int n);
機能:dをaのnで指定したshort値にコピーして,aを返します).se_pinsrw()の128ビット版.
戻値=(a.uhi[n&0x7]=d, a)
8.14.10 最大/最小値
xmm_t se2_pmaxsw128(xmm_t a, xmm_t b);
機能:並列最大short値.se_pmaxsw()の128ビット版.
戻値={ MAX(a.hi[0], b.hi[0]), ..., MAX(a.hi[7], b.hi[7]) }
xmm_t se2_pmaxub128(xmm_t a, xmm_t b);
機能:並列最大unsigned char値.se_pmaxub()の128ビット版.
戻値= { MAX(a.uqi[0], b.uqi[0]), ..., MAX(a.uqi[15], b.uqi[15]) }
xmm_t se2_pminsw128(xmm_t a, xmm_t b);
機能:並列最小short値.se_pminsw()の128ビット版.
戻値={ MIN(a.hi[0], b.hi[0]), ..., MIN(a.hi[7], b.hi[7]) }
xmm_t se2_pminub128(xmm_t a, xmm_t b);
機能:並列最小unsigned char値.se_pminub()の128ビット版.
戻値= { MIN(a.uqi[0], b.uqi[0]), ..., MIN(a.uqi[15], b.uqi[15]) }
8.14.11 符号ビットの取り出し
int se2_pmovmskb128(xmm_t a)
機能:aにある16個のsigned char値の最上位(符号ビット)を取り,16ビットマスクを構成して返します.se_pmovmskb()の128ビット版.
戻値=(a.qi[0]の符号ビット) | (((a.qi[1]の符号ビット)<<1) | ...
| (((a.qi[15]の符号ビット)<<15)
8.14.12 組み換え
xmm_t se2_pshufhw(xmm_t a, int n);
機能:v8hi型引数aの上位64ビットをnによって組み替えます.
戻値={ a.hi[0], ..., a.hi[3], a.hi[(n&0x3)+4], ..., a.hi[((n>>6)&0x3)+4] }
xmm_t se2_pshufhw_n3210(xmm_t a, int n3, int n2, int n1, int n0);
機能:v8hi型引数aの上位64ビットをn0, n1, n2, n3によって組み替えます.
戻値={ a.hi[0], ..., a.hi[3],
a.hi[n0+4], a.hi[n1+4], a.hi[n2+4], a.hi[n3+4] }
xmm_t se2_pshuflw(xmm_t a, int n);
機能:v8hi型引数aの下位64ビットをnによって組み替えます.
戻値={ a.hi[n&0x3], ..., a.hi[(n>>6)&0x3], a.hi[4], ..., a.hi[7] }
xmm_t se2_pshuflw_n3210(xmm_t a, int n3, int n2, int n1, int n0);
機能:v8hi型引数aの下位64ビットをn0, n1, n2, n3によって組み替えます.
戻値={ a.hi[n0], a.hi[n1], a.hi[n2], a.hi[n3],
a.hi[4], ..., a.hi[7] }
xmm_t se2_pshufd(xmm_t a, int n);
機能:v4si型引数aをnによって組み替えます.
戻値={ a.si[n&0x3], ..., a.si[(n>>6)&0x3] }
xmm_t se2_pshufd_n3210(xmm_t a, int n3, int n2, int n1, int n0);
機能:v4si型引数をn0, n1, n2, n3によって組み替えます.
戻値={ a.si[n0], a.si[n1], a.si[n2], a.si[n3] }
8.14.13 マスクによるデータの移動
void se2_maskmovdqu(xmm_t a, xmm_t n, char *p);
機能:v16qi型の引数nの各signed charの符号ビットが1であれば,対応するv16qi型引数aの
signed char値をpに保存されます.C言語風で説明すると,下記のコードの結果と同じです.se_maskmovq()の128ビット版.
int i; for (i = 0; i < 16; ++i) if (n.qi[i] < 0) p[i] =
a.qi[i];
8.14.14 平均値
xmm_t se2_pavgb128(xmm_t a, xmm_t b);
機能:v16qi型の符号なし平均.se_pavgb()の128ビット版.
戻値={ (a.uqi[0]+b.uqi[0])/2, ..., (a.uqi[15]+b.uqi[15])/2 }
xmm_t se2_pavgw128(xmm_t a, xmm_t b);
機能:v8hi型の符号なし平均.se_pavgw()の128ビット版.
戻値= { (a.uhi[0]+b.uhi[0])/2, ..., (a.uhi[7]+b.uhi[7])/2 }
8.14.15 差の絶対値の合計
xmm_t se2_psadbw128(xmm_t a, xmm_t b);
機能:v16qi型の符号なし差の絶対値の合計.se_psadbw()の128ビット版.
戻値=(v8hi){ |a.uqi[0]-b.uqi[0]|+,...,+|a.uqi[7]-b.uqi[7]|, 0, 0, 0,
|a.uqi[8]-b.uqi[8]|+,...,+|a.uqi[15]-b.uqi[15]|, 0, 0, 0 }
8.15 非一時保存
void se2_movnti(int *a, int b);
機能:キャッシュレス保存.*a = b;
void se2_movntdq(xmm_t *a, xmm_t b);
機能:キャッシュレス保存.*a = b;
void se2_movntpd(double *p, xmm_t a);
機能:キャッシュレス保存.*(xmm_t *)p = a;
8.16 キャッシュのフラッシュ
void se2_clflush(void const *ptr);
機能:ptrを含むキャッシュラインをフラッシュします.
8.17 柵
void se2_lfence(void);
機能:この関数より前にロードしたデータがすべて“見える”状態にします.
void se2_mfence(void);
機能:この関数より前に保存したデータ/ロードしたデータがすべて“見える”状態にします.