リバースエンジニアリングへの道 - その13

# リバースエンジニアリングへの道
出田 守です。
最近、情報セキュリティに興味を持ち、『リバースエンジニアリング-Pythonによるバイナリ解析技法』という本(以降、「教科書」と呼びます)を読みました。
「こんな世界があるのか！かっこいい！」と感動し、私も触れてみたいということでド素人からリバースエンジニアリングができるまでを書いていきたいと思います。
ちなみに、教科書ではPython言語が使用されているので私もPython言語を使用しています。
ここを見ていただいた諸先輩方からの意見をお待ちしております。

## 軌跡
[リバースエンジニアリングへの道 - その12](https://qiita.com/deta-mamoru/items/5353dccc071070409f11)

## 環境
OS: Windows10 64bit Home (日本語)
CPU: Intel® Core™ i3-6006U CPU @ 2.00GHz × 1
メモリ: 2048MB
Python: 3.6.5

私の環境は、普段Ubuntu16.04を使っていますが、ここではWindows10 64bitを仮想マシン上で立ち上げております。
ちなみに教科書では、Windowsの32bitで紹介されています。

## Intel Deveroper's Manual [1] Chapter11 - Chapter12
現在CPU周りの知識をつけるために『Intel Software Developer's Manual(IDMと呼びます)』をさっくりまとめています。
[前回](https://qiita.com/deta-mamoru/items/5353dccc071070409f11)はIDMのChapter10までをまとめました。なお、画像は全てIDMより掲載しています。
今回はChapter11 - Chapter12までをまとめます。

## CHAPTER 11 PROGRAMMING WITH INTEL STREAMING SIMD EXTENSIONS 2 (INTEL SSE2)
Streaming SIMD extensions 2(SSE2)はPentium 4プロセッサとIntel XeonプロセッサのIA-32アーキテクチャに導入されました。これらの拡張は3D画像、ビデオデコード/エンコード、音声認識、Eコマース、インターネット、科学、アプリケーションにおけるIA-32プロセッサのパフォーマンスを強化します。

### 11.1 OVERVIEW OF SSE2 EXTENSIONS
SSE2拡張はMMXテクノロジとSSE拡張とともに使われるsingle instruction multiple data(SIMD)拡張モデルを使用します。これらはパックされた倍精度浮動小数点と128bitのパックされた整数のサポートでこのモデルを拡張します。
もしCPUID.01H:EDX.SSE2[bit 26] = 1であれば、SSE2拡張は存在します。

SSE2拡張は全ての既存のIA-32プロセッサ、アプリケーション、OSの後方互換を保ちながらIA-32アーキテクチャへ次に示す機能を追加します。

- 6つのデータ型:
  - 128bitのパックされた倍精度浮動小数点(2つのIEEE Standard 754倍精度浮動小数点がDqwordにパックされる)
  - 128bitのパックされたByte整数
  - 128bitのパックされたWord整数
  - 128bitのパックされたDword整数
  - 128bitのパックされたQword整数
- 追加のデータ型をサポートし、既存のSIMD整数演算を拡張するための命令:
  - パックされた倍精度浮動小数点命令またはスカラ倍精度浮動小数点命令
  - 追加の64bitと128bitのSIMD整数命令
  - MMXテクノロジとSSE拡張に導入されたSIMD整数命令の128bitバージョン
  - 追加のキャッシュ制御命令と命令順序命令
- SSE2機能をサポートするために既存のIA-32命令の変更
  - CPUID命令の拡張と変更
  - RDPMC命令の変更

これらは新しい機能を3つの重要な方法でIA-32アーキテクチャのSIMDプログラミングモデルに拡張します。

- パックされた倍精度浮動小数点値のペアに対してSIMD演算を実行する機能を提供します。これにより、XMMレジスタでより高い精度の計算を実行できるようになり、科学およびアプリケーションや高度な3 -Dジオメトリ技法(レイトレーシングなど)を使ったアプリケーションのパフォーマンスを強化します。追加の柔軟性は、XMMレジスタの下位Qwordにある単一(スカラー)倍精度浮動小数点値で動作する命令で提供されます。
- XMMレジスタの128bitのパックされた整数(Byte、Word、Dword、Qword)を操作する機能を提供します。これにより、パックされた整数に対してSIMD演算を実行する際の柔軟性が向上し、スループットが向上します。この機能は、RSA認証やRC5暗号化などのアプリケーションに特に役立ちます。SIMDレジスタ、データ型、MMXとSSE/SSE2拡張で提供される命令の全ての命令を使って、プログラマはパックされた単精度浮動小数点と倍精度浮動小数点、64bitと128bitのパックされた整数を細かく混合したアルゴリズムを開発することが出来ます。
- SSE2拡張は、SIMDデータのキャッシュを制御するためにSSE拡張で導入されたサポートを強化します。SSE2キャッシュ制御命令は、キャッシュを汚染することなく、また実際に使用される前にデータをプリフェッチすることなく、XMMレジスタ内外のデータをストリームする機能を提供します。

SSE2拡張は、IA-32プロセッサ用に作成されたすべてのソフトウェアと完全に互換性があります。既存のソフトウェアはすべて、SSE2拡張機能を組み込んだプロセッサ、およびこれらの拡張機能を組み込んだアプリケーションの下で、修正なしで正しく動作し続けます。CPUID命令の拡張により、SSE2拡張の検出が可能になります。また、SSE2拡張機能はSSE拡張機能と同じレジスタを使用するため、SSE拡張機能用に提供されたものを超えてコンテキスト切り替え中にプログラム状態を保存および復元するための新しいOSサポートは必要ありません。
SSE2拡張は、すべてのIA-32実行モード(保護モード、実アドレスモード、仮想8086モード)からアクセスできます。
この章の以下のセクションでは、128bitXMM浮動小数点レジスタセット、データ型、およびSSE2命令を含むSSE2拡張のプログラミング環境について説明します。また、SSEおよびSSE2命令で生成できる例外についても説明し、SSEおよびSSE2拡張を使用してアプリケーションを作成するためのガイドラインを示します。

### 11.2 SSE2 PROGRAMMING ENVIRONMENT
図11-1はSSE2拡張のプログラミング実行環境を表しています。
新しいレジスタやその他の命令実行状態は、SSE2拡張で定義されていません。SSE2命令は、次のようにXMMレジスタ、MMXレジスタ、および/またはIA-32汎用レジスタを使用します。

- XMMレジスタ  
  パックされたまたはスカラの倍精度浮動小数点データの操作には、これらの8つのレジスタ(図10-2を参照)を使用します。スカラ演算は、XMMレジスタの下位Qwordに格納された個々の(アンパックされた)倍精度浮動小数点値に対して実行される演算です。XMMレジスタは、128bitのパックされた整数データの操作を実行するためにも使用されます。これらは、XMM0-7という名前で参照されます。
- MXCSRレジスタ  
  この32bitレジスタ(図10-3を参照)は、浮動小数点演算で使用されるステータスbitと制御bitを提供します。このレジスタのdenormals-are-zerosとflush-to-zeroフラグは、denormalソースオペランドおよびdenormal(アンダーフロー)結果の処理のためのより高性能な代替を提供します。詳しくはSection 10.2.3.4とSection 10.2.3.3を参照。
- MMXレジスタ  
  これら8つのレジスタ(図9-2参照)は、64bitのパックされた整数データに対して演算を実行するために使用されます。また、MMXレジスタとXMMレジスタ間で実行されるオペレーションのオペランドを保持するためにも使用されます。MMXレジスタはMM0-7という名前で参照されます。
- 汎用レジスタ  
  8つの汎用レジスタ(図3-5参照)は、既存のIA-32アドレッシングモードと共に使用され、メモリ内のオペランドをアドレス指定します。MMXおよびXMMレジスタを使用してメモリをアドレス指定することはできません。汎用レジスタは、一部のSSE2命令のオペランドを保持するためにも使用されます。これらのレジスタは、EAX、EBX、ECX、EDX、EBP、ESI、EDI、およびESPの名前で参照されます。
- EFLAGSレジスタ  
  この32bitレジスタ(図3-8参照)はいくつかの比較操作の結果を記録するために使用されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/2e607649-2c09-02ee-4082-03450c8e711f.png)


#### 11.2.1 SSE2 in 64-Bit Mode and Compatibility Mode
互換モードでは、SSE拡張は保護モードと同様に機能します。64bitモードでは、8つの追加XMMレジスタが利用可能です。レジスタはREXプレフィクスを使ってXMM8-15でアクセスできます。
メモリオペランドはSection 3.7.5で説明したModR/M、SIBエンコードを使って指定されます。
いくつかのSSE2命令は汎用レジスタに対して操作するために使われるかもしれません。64bit汎用レジスタにアクセスするためにはREX.Wプレフィクスを使ってください。もしREXプレフィクスが意味を持たない場合、プレフィクスは無視されることに注意してください。

#### 11.2.2 Compatibility of SSE2 Extensions with SSE, MMX Technology and x87 FPU Programming Environment
SSE2拡張は、SSEの拡張を超えてIA-32実行環境に新しい状態を導入しません。SSE2拡張は、SSE拡張の拡張を表します。それらは完全に互換性があり、同じ状態情報を共有します。SSEとSSE2命令は、命令セットの切り替え時に状態を保存する必要なく、同じ命令ストリーム内で一緒に実行できます。XMMレジスタはx87 FPUおよびMMXレジスタとは独立しています。XMMレジスタで実行されるSSEおよびSSE2の操作は、x87 FPUまたはMMXテクノロジの操作(Section 11.6.7を参照)と並行して実行できます。
FXSAVEおよびFXRSTOR命令は、SSEおよびSSE2の状態をx87 FPUおよびMMXの状態とともに保存および復元します。

#### 11.2.3 Denormals-Are-Zeros Flag
Denormals-are-zerosフラグはSSE2拡張のIA-32アーキテクチャに導入されました。Section 10.2.3.4を参照してください。

### 11.3 SSE2 DATA TYPES
SSE2拡張は一つの128bitのパックされた浮動小数点データと4つの128bitのSIMD整数データ型をIA-32アーキテクチャに導入されました(図11-2参照)。

- パックされた倍精度浮動小数点  
  この128bitのデータ型は、Dqwordにパックされた2つのIEEE 64bit倍精度浮動小数点値で構成されています。Section 11.6.7を参照してください。
- 128bitのパックされた整数  
  4つの128bitのパックされた整数は16Byte整数または8Word整数、4Dword整数、2Qword整数で構成することが出来ます(Section 4.6.2を参照)。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/14eff005-4bda-c7d4-2ec5-ff4d680d30d7.png)


これらのデータ型はすべて、XMMレジスタまたはメモリで操作されます。これらの128bitデータタイプと64bitトおよび32bitデータタイプとの間で変換するための命令が提供されます。
128bitのパックされたメモリオペランドのアドレスは、次の場合を除いて16Byteの境界に揃えなければなりません。

- 整列されていないアクセスをサポートしたMOVUPD命令
- 8Byteのメモリオペランドを使用するスカラ命令で、アライメントの要件に従わないもの
 
図4-2はメモリの128bit(Dqword)あるいは64bit(Qword)データ型のByte順を表しています。

### 11.4 SSE2 INSTRUCTIONS
SSE2命令は4つの機能グループに分けられます。

- パックされた倍精度浮動小数点命令あるいはスカラ倍精度浮動小数点命令
- 64bitあるいは128bitのSIMD整数命令
- MMXテクノロジとSSE拡張に導入されたSIMD整数命令の128bitバージョン
- キャッシュ制御と命令順序命令

#### 11.4.1 Packed and Scalar Double-Precision Floating-Point Instructions
パックされた倍精度浮動小数点命令あるいはスカラ倍精度浮動小数点命令は次のサブグループに分けられます。

- データ転送命令
- 算術命令
- 比較命令
- 変換命令
- 論理命令
- シャッフル命令

パックされた倍精度浮動小数点命令はパックされた単精度浮動小数点命令と似たようなSIMD操作を実行します(図11-3参照)。各ソースオペランドには2つの倍精度浮動小数点を含み、宛先オペランドには各オペランドに対応した値(X0とY0, X1とY1)に対して並列で実行された操作(OP)の結果を含みます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/af994220-210a-0c5c-eb95-6f89e366cdc4.png)

スカラ倍精度浮動小数点命令は、図11-4に示すように、2つのソースオペランド(X0およびY0)の下位(最下位)のQwordで動作します。最初のソースオペランドの上位Qword(X1)が宛先にパススルーされます。スカラ演算は、倍精度(53ビットの仮数)に設定されたx87 FPU制御Wordの精度制御フィールドを持つx87 FPUデータレジスタで実行される浮動小数点演算と似ていますが、x87スタック演算では15bitの指数、SSE2演算では11bitの指数範囲を使用します。
XMMレジスタとx87 FPUデータレジスタでスカラ倍精度浮動小数点演算を実行するときの互換性のある結果を得るための詳細は、Section 11.6.8を参照してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/2d0f84c5-4fbf-dea1-04cd-c2c2ed3f0588.png)

##### 11.4.1.1 Data Movement Instructions
データ移動命令は、倍精度浮動小数点データをXMMレジスタ間およびXMMレジスタとメモリ間で移動します。
MOVAPD命令は、128bitのパックされた倍精度浮動小数点オペランドをメモリからXMMレジスタに、またはその逆、またはXMMレジスタ間で転送します。メモリアドレスは16Byteの境界に揃えなければなりません。そうでなければ、一般保護例外(GP#)が生成されます。
MOVUPD命令は、128bitのパックされた倍精度浮動小数点オペランドをメモリからXMMレジスタに、またはその逆、またはXMMレジスタ間で転送します。メモリアドレスのアラインメントは必要ありません。
MOVSD命令は、64bit倍精度浮動小数点オペランドをメモリからXMMレジスタの下位Qwordに、またはその逆、またはXMMレジスタ間で転送します。アライメントチェックが有効になっていない限り、メモリアドレスのアラインメントは必要ありません。
MOVHPD命令は、メモリから64bitの倍精度浮動小数点オペランドをXMMレジスタの上位Qwordに、またはその逆に転送します。レジスタの下位Qwordは変更されません。アライメントチェックが有効になっていない限り、メモリアドレスのアラインメントは必要ありません。
MOVLPD命令は、メモリから64bitの倍精度浮動小数点オペランドをXMMレジスタの下位Qwordに、またはその逆に転送します。レジスタの上位Qwordは変更されません。アライメントチェックが有効になっていない限り、メモリアドレスのアラインメントは必要ありません。
MOVMSKPD命令は、パックされた2つの倍精度浮動小数点数の符号bitをXMMレジスタで抽出し、汎用レジスタに保存します。この2bitの値は、分岐を実行するための条件として使用できます。

##### 11.4.1.2 SSE2 Arithmetic Instructions
SSE2算術命令は、パックされた倍精度浮動小数点値およびスカラ倍精度浮動小数点値に対する加算、減算、乗算、除算、平方根、最大/最小演算を実行します。
ADDPD命令とSUBPD命令は、それぞれ2つのパックされた倍精度浮動小数点オペランドを加算および減算します。
ADDSDおよびSUBSD命令は、2つのオペランドの下位倍精度浮動小数点値をそれぞれ加算および減算し、その結果を宛先オペランドの下位Qword。
MULPD命令は、2つのパックされた倍精度浮動小数点オペランドを乗算します。
MULSD命令は、2つのオペランドの下位倍精度浮動小数点値を乗算し、結果を宛先オペランドの下位Qwordに格納します。
DIVPD命令は、2つのパックされた倍精度浮動小数点オペランドを除算します。
DIVSD命令は、2つのオペランドの下位倍精度浮動小数点値を除算し、その結果を宛先オペランドの下位Qwordに格納します。
SQRTPD命令は、パックされた倍精度浮動小数点オペランドの値の平方根を計算します。
SQRTSD命令は、ソースオペランド内の下位倍精度浮動小数点値の平方根を計算し、その結果を宛先オペランドの下位Qwordに格納します。
MAXPD命令は、パックされた2つの倍精度浮動小数点オペランドの対応する値を比較し、各比較からの数値が大きい方の値を宛先オペランドに返します。
MAXSD命令は、2つのパックされた倍精度浮動小数点オペランドの下位倍精度浮動小数点値を比較し、その比較から数値の高い方の値を宛先オペランドに返します。
MINPD命令は、パックされた2つの倍精度浮動小数点オペランドの対応する値を比較し、各比較から宛先オペランドに数値的に小さい値を返します。
MINSD命令は、パックされた2つの倍精度浮動小数点オペランドの下位値を比較し、その比較から数値の小さい値を宛先オペランドの下位Qwordに戻します。

##### 11.4.1.3 SSE2 Logical Instructions
SSE2論理命令は、パックされた倍精度浮動小数点値に対してAND、NOT、OR、およびXOR演算を実行します。
ANDPD命令は、2つのパックされた倍精度浮動小数点オペランドのANDを返します。
ANDNPD命令は、2つのパックされた倍精度浮動小数点オペランドのAND NOTを戻します。
ORPD命令は、2つのパックされた倍精度浮動小数点オペランドのORを返します。
XORPD命令は、パックされた2つの倍精度浮動小数点オペランドのXORを返します。

##### 11.4.1.4 SSE2 Comparison Instructions
SSE2の比較命令は、パックされたスカラ倍精度浮動小数点値とスカラ倍精度浮動小数点値を比較し、比較結果を宛先オペランドまたはEFLAGSレジスタに返します。
CMPPD命令は、2つのパックされた倍精度浮動小数点オペランドの対応する値を、即値オペランドを使用して比較し、比較ごとにすべての1またはすべて0の64bitマスク結果を宛先オペランドに戻します。即値オペランドの値は、等しい、より小さい、等しいより小さい、順序付けられていない、等しくない、より小さくない、等しいより小さくない、または順序付けされた8つの比較条件のいずれかを選択することができます。
CMPSD命令は、2つのパックされた倍精度浮動小数点オペランドの下位値を、即値オペランドを使用して比較し、すべての1またはすべての0の64ビットマスク結果を宛先オペランドの下位Qwordに返します。即値オペランドは、CMPPD命令と同様に比較条件を選択します。
COMISD命令とUCOMISD命令は、2つのパックされた倍精度浮動小数点オペランドの下位値を比較し、 EFLAGSレジスタのZF、PF、およびCFフラグを使用して、結果を表示します(より大きい、より小さい、等しい、または順不同)。これらの2つの命令は、次のように異なります。COMISD命令は、ソースオペランドがQNaNまたはSNaNの場合は浮動小数点無効操作(#I)例外を通知します。ソースオペランドがSNaNである場合、UCOMISD命令は無効操作例外のみを通知します。

##### 11.4.1.5 SSE2 Shuffle and Unpack Instructions
SSE2シャッフル命令は、2つのパックされた倍精度浮動小数点値の内容をシャッフルし、結果を宛先オペランドに格納します。
SHUFPD命令は、宛先オペランドの2つのパックされた倍精度浮動小数点値のいずれかを宛先オペランドの下位Qwordに配置し、ソースオペランドの2つのパックされた倍精度浮動小数点値のいずれかを宛先オペランドの上位4ワード内に配置します(図11-5を参照)。ソースと宛先のオペランドに同じレジスタを使用することにより、SHUFPD命令は2つのパックされた倍精度浮動小数点値をスワップできます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/cedf9b2c-596a-bb21-6950-edfda5733ed5.png)

UNPCKHPD命令は、ソースオペランドと宛先オペランドからの高値のインターリーブアンパッキングを実行し、結果を宛先オペランドに格納します(図11-6を参照)。
UNPCKLPD命令は、ソースオペランドと宛先オペランドから低値のインターリーブアンパックを実行し、その結果を宛先オペランドに格納します(図11-7参照)。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/4ac97b10-74a9-c347-af36-ae3646413dba.png)

##### 11.4.1.6 SSE2 Conversion Instructions
SSE2変換命令(図11-8を参照)は、次の間のパックされたおよびスカラ変換をサポートします。

- 倍精度および単精度浮動小数点形式
- 倍精度浮動小数点およびDword整数形式
- 単精度浮動小数点およびDword整数形式

倍精度浮動小数点値と単精度浮動小数点値間の変換 - 以下の命令は、オペランドを倍精度浮動小数点形式と単精度浮動小数点形式との間で変換します。操作対象のオペランドは、XMMレジスタまたはメモリに格納されます(多くの場合、1つのオペランドはメモリに常駐できます;宛先は常にMMXレジスタです)。
CVTPS2PD命令は、パックされた2つの単精度浮動小数点値を2つの倍精度浮動小数点値に変換します。
CVTPD2PS命令は、2つのパックされた倍精度浮動小数点値を2つの単精度浮動小数点値に変換します。変換が不正確な場合、結果はMXCSRレジスタで選択された丸めモードに従って丸められます。
CVTSS2SD命令は、単精度浮動小数点値を倍精度浮動小数点値に変換します。
CVTSD2SS命令は、倍精度浮動小数点値を単精度浮動小数点値に変換します。変換が不正確な場合、結果はMXCSRレジスタで選択された丸めモードに従って丸められます。
倍精度浮動小数点値とDword整数間の変換 - 次の命令は、倍精度浮動小数点数型とDword整数形式の間でオペランドを変換します。オペランドは、XMMレジスタ、MMXレジスタ、汎用レジスタまたはメモリに格納されます(最大でも1つのオペランドはメモリに常駐できます;宛先は常にXMM、MMX、または汎用レジスタです)。
CVTPD2PI命令は、2つのパックされた倍精度浮動小数点数を2つのパックされた符号付きDword整数に変換し、その結果をMMXレジスタに格納します。整数値に丸める場合、ソース値はMXCSRレジスタの丸めモードに従って丸められます。
CVTTPD2PI命令は、切り捨てを使用してソースの値を整数値に丸めることを除いて、CVTPD2PI命令と同様です(Section 4.8.4.2を参照してください)。
CVTPI2PD命令は、2つのパックされた符号付きDword整数を2つの倍精度浮動小数点値に変換します。
CVTPD2DQ命令は、2つのパックされた倍精度浮動小数点数を2つのパックされた符号付きDword整数に変換し、その結果をXMMレジスタの下位Qwordに格納します。整数値を四捨五入する場合、ソースの値はMXCSRレジスタで選択された丸めモードに従って丸められます。
CVTTPD2DQ命令はCVTPD2DQ命令に似ていますが、切り捨てを使用してソースの値を整数値に丸めます。
CVTDQ2PD命令は、XMMレジスタの下位Dwordにある2つのパックされた符号付きDword整数を2つの倍精度浮動小数点値に変換します。
CVTSD2SI命令は、倍精度浮動小数点値をDword整数に変換し、その結果を汎用レジスタに格納します。整数値を四捨五入する場合、ソースの値はMXCSRレジスタで選択された丸めモードに従って丸められます。
CVTTSD2SI命令は、切り捨てを使用してソースの値を整数値に丸めることを除いて、CVTSD2SI命令と似ています。
CVTSI2SD命令は、汎用レジスタの符号付きDword整数を倍精度浮動小数点数に変換し、その結果をXMMレジスタに格納します。
単精度浮動小数点型と倍精度浮動小数点型間の変換 - これらの命令は、パックされた単精度浮動小数点型とパックされたDword整数型の間で変換します。オペランドは、XMMレジスタ、MMXレジスタ、汎用レジスタ、またはメモリ(最大で1つのソースオペランド)に格納されます。宛先は常にXMM、MMX、または汎用レジスタです。これらのSSE2命令は、SSE拡張で導入された変換命令(CVTPI2PS、CVTPS2PI、CVTTPS2PI、CVTSI2SS、CVTSS2SI、CVTTSS2SI)を補完します。
CVTPS2DQ命令は、4つのパックされた単精度浮動小数点値を4つのパックされた符号付きDword整数に変換し、ソースオペランドと宛先オペランドはXMMレジスタまたはメモリに格納します(最大で1つのソースオペランド)。変換が不正確である場合、MXCSRレジスタで選択された丸めモードに従って丸められた値が返されます。
CVTTPS2DQ命令は、切り捨てがソースの値を整数値に丸めるために使用される点を除いて、CVTPS2DQ命令と似ています。
CVTDQ2PS命令は、4つのパックされた符号付きDword整数を、パックされた単精度浮動小数点数に変換します。ソースおよび宛先オペランドは、XMMレジスタまたはメモリに格納されます(最大で1つのソースオペランド）。変換が不正確である場合、MXCSRレジスタで選択された丸めモードに従って丸められた値が返されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/c418c025-f9ca-621a-2a9d-6a83fd4edf4d.png)


#### 11.4.2 SSE2 64-Bit and 128-Bit SIMD Integer Instructions
SSE2拡張は、いくつかの128bitのパックされた整数命令をIA-32アーキテクチャに追加します。必要に応じて、これらの命令のそれぞれの64bitバージョンも提供されています。128bitバージョンの命令は、XMMレジスタのデータを操作します。64bitバージョンはMMXレジスタのデータを操作します。命令は次のとおりです。
MOVDQA命令は、メモリからXMMレジスタへ、またはその逆に、Dwordオペランドをメモリから転送しますまたはXMMレジスタ間で実行できます。メモリアドレスは16Byteの境界に揃えなければなりません。それ以外の場合は、一般保護例外(#GP)が生成されます。
MOVDQU命令は、メモリアドレスの16Byteアラインメントが不要である点を除いて、MOVDQA命令と同じ操作を実行します。
PADDQ命令は、2つのパックされたQword整数オペランドまたは2つのシングルQword整数オペランドを加算し、その結果をそれぞれXMMまたはMMXレジスタに格納します。この命令は、符号なしまたは符号付き(2の補数表記)の整数オペランドで動作できます。
PSUBQ命令は、2つのパックされたQword整数オペランドまたは2つのシングルQword整数オペランドを減算し、その結果をそれぞれXMMまたはMMXレジスタに格納します。PADDQ命令と同様に、PSUBQは符号なしまたは符号付き(2の補数表記)の整数オペランドで動作できます。
PMULUDQ命令は、符号なしDword整数の符号なし乗算を実行し、Qword結果を返します。この命令は64bitバージョンと128ビットバージョンの両方が使用できます。64bitバージョンは、各ソースオペランドの下位Dwordに格納された2つのDword整数で動作し、Qwordの結果はMMXレジスタに戻されます。 128bitバージョンは、2つのDword整数のパックされた乗算を実行します。ここでは、Dwordはソースオペランドの第1および第3のDwordにパックされ、Qwordの結果はXMMレジスタの下位および上位Qwordに格納されます。
PSHUFLW命令は、ソースオペランドの下位QwordにパックされたWordをシャッフルし、シャッフルされた結果を宛先オペランドの下位Qwordに格納します。8bitの即値オペランドがシャッフル順序を指定します。
PSHUFHW命令は、ソースオペランドの上位QwordにパックされたWordをシャッフルし、シャッフルされた結果を宛先オペランドの上位Qwordに格納します。8bitの即値オペランドがシャッフル順序を指定します。
PSHUFD命令は、ソースオペランドにパックされたDword整数をシャッフルし、シャッフルされた結果を宛先オペランドに格納する。8bitの即値オペランドがシャッフル順序を指定します。
PSLLDQ命令は、ソースオペランドの内容を、即値オペランドによって指定されたByte量だけ左にシフトする。空の下位Byteがクリアされます(0に設定されます)。
PSRLDQ命令は、ソースオペランドの内容を即値オペランドによって指定されたByte数だけ右にシフトします。空の上位Byteがクリアされます(0に設定されます)。
PUNPCKHQDQ命令は、ソースオペランドの上位Qwordと宛先オペランドの上位Qwordをインタリーブし、宛先レジスタに書き込みます。
PUNPCKLQDQ命令は、ソースオペランドの下位4Wordと宛先オペランドの下位4Wordをインターリーブし、それらを宛先レジスタに書き込みます。
SSE命令を2つ追加すると、MMXレジスタからXMMレジスタへのデータ移動が可能になります。
MOVQ2DQ命令は、Qword整数をMMXソースレジスタからXMMデスティネーションレジスタに移動します。
MOVDQ2Q命令は、XMMソースレジスタからMMX宛先レジスタに下位Qword整数を移動します。

#### 11.4.3 128-Bit SIMD Integer Instruction Extensions
MMXテクノロジおよびSSE拡張(PSHUFW命令を除く)で導入されたすべての64bit SIMD整数命令は、SSE2拡張によって拡張され、XMMレジスタに配置された128bitのパックされた整数オペランドで動作します。これらの命令の128bitバージョンは、64ビットバージョンと同様にパックされたオペランドに関する同じSIMD規則に従います。たとえば、PADDB命令の64bitバージョンが8パックされたByteで動作する場合、128bitバージョンは16パックされたByteで動作します。

#### 11.4.4 Cacheability Control and Memory Ordering Instructions
SSE2拡張機能により、プログラムはデータのキャッシュ、読み込み、および格納をより詳細に制御できます。

##### 11.4.4.1 FLUSH Cache Line
CLFLUSH命令は、指定されたリニアアドレスに関連するキャッシュラインの書き込みおよび無効化を行います。無効化は、プロセッサのキャッシュ階層のすべてのレベルに対して行われ、キャッシュコヒーレンシドメイン全体にブロードキャストされます。

>CLFLUSHはSSE2拡張で導入されました。ただし、SSE2拡張を実装していないIA-32プロセッサでも命令を実装できます。フィーチャビット(CPUID.01H：EDX.CLFSH [ビット19] = 1の場合)を使用してCLFLUSHを検出します。

##### 11.4.4.2 Cacheability Control Instructions
以下の4つの命令は、non-temporal hintを使用して、XMMおよび汎用レジスタからのデータをメモリに格納することを可能にします。non-temporal hintは、データをキャッシュ階層に書き込むことなく、プロセッサにメモリにデータを格納するように指示します。non-temporal storeとhintの詳細は、Section 10.4.6.2を参照してください。
MOVNTDQ命令は、non-temporal hintを使用して、パックされた整数データをXMMレジスタからメモリに格納します。
MOVNTPD命令は、non-temporal hintを使用して、パックされた倍精度浮動小数点データをXMMレジスタからメモリに格納します。
MOVNTI命令は、non-temporal hintを使用して、汎用レジスタからメモリに整数データを格納します。
MASKMOVDQU命令は、Byteマスクを使用して個々のByteを選択的に書き込むことにより、XMMレジスタから選択されたByte整数をメモリに格納します。メモリの場所は、自然な境界に位置合わせする必要はありません。この命令は、non-temporal hintも使用します。

##### 11.4.4.3 Memory Ordering Instructions
SSE2拡張では、SSE拡張で導入されたSFENCE命令のコンパニオンとして、2つの新しいフェンス命令(LFENCEとMFENCE)が導入されています。
LFENCE命令は、読み込みのためのメモリフェンスを確立します。2つの読み込みの間の順序を保証し、投機的な読み込みがロードフェンスを通過するのを防ぎます(つまり、ロードフェンスの前に指定されたすべての読み込みが実行されるまで投機的な読み込みは許可されません)。
MFENCE命令は、読み込みと格納の両方に対してメモリフェンスを確立します。プロセッサは、MFENCEの前のすべての読み込みと格納がグローバルに表示されるまで、MFENCEの後に読み込みまたは格納がグローバルに表示されないようにします。LFENCE; SFENCEとSFENCE; LFENCEのシーケンスはMFENCEと等価ではないことに注意してください。どちらも、古いストアがより若い負荷の前にグローバルに観察されることを保証しないためです。

##### 11.4.4.4 Pause
PAUSE命令は、Pentium 4またはIntel Xeonプロセッサ上で実行される「spin-wait loops」のパフォーマンスを向上させるために提供されています。Pentium 4プロセッサでは、spin-wait loopsを実行しながらプロセッサ消費電力を削減するという追加の利点も提供します。spin-wait loopsのコードシーケンスには常にPAUSE命令を含めることを推奨します。

#### 11.4.5 Branch Hints
SSE2拡張は、2つの命令プレフィックス（2EHおよび3EH）を指定して、プロセッサにbranch hintを提供します(2AのChapter2を参照)。これらのプレフィクスは、Jcc命令でのみ使用でき、マシンコードレベルでのみ使用できます(つまり、branch hintのニーモニックはありません)。

### 11.5 SSE, SSE2, AND SSE3 EXCEPTIONS
SSE/SSE2/SSE3拡張は、2つの一般的なタイプの例外を生成します。

- Non-numeric例外
- SIMD浮動小数点例外(SSE3のFISTTP命令はSIMD浮動小数点例外を生成しませんが、x87 FPU浮動小数点例外を生成する可能性があります。)

SSE/SSE2/SSE3命令は、他のIA-32アーキテクチャ命令と同じタイプのメモリアクセス例外およびnon-numeric例外を生成できます。既存の例外ハンドラは、コード変更なしでこれらの例外を処理することが一般的です。3のChapter13を参照してください。SSE/SSE2/SSE3命令およびこれらの例外を処理するためのガイドラインによって生成することができます。
SSE/SSE2/SSE3命令は、パックされた整数演算でnumeric例外を生成しません。ただし、パックされた単精度および倍精度浮動小数点演算でnumeric(SIMD浮動小数点)例外を生成することができます。これらのSIMD浮動小数点例外は、バイナリ浮動小数点演算のIEEE Standard 754で定義されており、x87 FPU命令で生成されるのと同じ例外です。これらの例外の説明については、Section 11.5.1を参照してください。

#### 11.5.1 SIMD Floating-Point Exceptions
SIMD浮動小数点例外は、パックされたスカラ浮動小数点オペランドまたはスカラー浮動小数点オペランドで動作するSSE/SSE2/SSE3命令によって生成される例外です。
6つのクラスのSIMD浮動小数点例外を生成することができます。

- Invalid operation (#I)
- Divide-by-zero (#Z)
- Denormal operand (#D)
- Numeric overflow (#O)
- Numeric underflow (#U)
- Inexact result (Precision) (#P)

これらの例外(denormalオペランド例外を除く)はすべて、IEEE Standard 754で定義されており、x87浮動小数点命令で生成されるのと同じ例外です。Section 4.9では、これらの例外、および生成される方法とタイミングについて詳しく説明しています。以下のセクションでは、SSE/SSE2/SSE3拡張でのこれらの例外の実装について説明します。
すべてのSIMD浮動小数点例外は正確であり、命令の実行が完了するとすぐに発生します。
MXCSRレジスタの対応するフラグ(IE、DE、ZE、OE、UE、PE)とマスクbit(IM、DM、ZM、OM、UM、PM)は6つの例外条件のそれぞれにあります(図10- 3)。マスクbitはLDMXCSRまたはFXRSTOR命令で設定できます。STMXCSRまたはFXSAVE命令を使用して、マスクおよびフラグbitを読み取ることができます。
制御レジスタCR4のOSXMMEXCEPTフラグ(bit 10)は、OSがSIMD浮動小数点例外に対するソフトウェア例外ハンドラをサポートしているかどうかを示すことによってSIMD浮動小数点例外の生成をさらに制御します。マスクされていないSIMD浮動小数点例外が生成され、OSXMMEXCEPTフラグがセットされている場合、プロセッサはSIMD浮動小数点例外(#XM)を生成してソフトウェア例外ハンドラを呼び出します。OSXMMEXCEPT bitがクリアされている場合、プロセッサはSIMD浮動小数点例外条件を検出する最初のSSEまたはSSE2命令で無効オペコード例外(#UD)を生成します。Section 11.6.2を参照してください。

#### 11.5.2 SIMD Floating-Point Exception Conditions
以下のセクションでは、SIMD浮動小数点例外が発生する条件と、これらの条件が検出されたときのプロセッサのマスクされた応答について説明します。
命令に対して複数の浮動小数点例外条件が検出された場合の例外優先順位の規則については、Section 4.9.2を参照してください。

##### 11.5.2.1 Invalid Operation Exception (#I)
浮動小数点無効演算例外(#I)は、無効な演算オペランドに応答して発生します。無効演算例外のフラグ(IE)bitとマスク(IM)bitは、それぞれMXCSRレジスタのbit0とbit7です。
無効操作例外がマスクされている場合、プロセッサは実行される操作に応じて、QNaN、QNaN浮動小数点不定、整数不定、ソースオペランドの1つを宛先オペランドに返すか、またはEFLAGSを設定します。値が宛先オペランドに戻されると、その命令によって指定された宛先レジスタが上書きされます。表11-1に、プロセッサが命令で検出した無効算術演算と、これらの演算に対するマスクされた応答を示します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/680c5b54-85bc-572a-fd66-c576291edb2a.png)

無効操作例外がマスクされていない場合、ソフトウェア例外ハンドラが呼び出され、オペランドは変更されません。Section 11.5.4項を参照してください。
通常、1つまたは複数のソースオペランドがQNaN(いずれもSNaNでもサポートされていない形式でもない)の場合、無効操作例外は生成されません。COMISS命令とCOMISD命令、CMPPS、CMPSS、CMPPD、CMPSD命令は例外です。これらの命令では、QNaNソース・オペランドは無効操作例外を生成します。
無効操作例外は、flush-to-zeroモードまたはdenormals-are-zeroモードの影響を受けません。

##### 11.5.2.2 Denormal-Operand Exception (#D)
算術命令がDenormalのオペランドに対して操作しようとすると、プロセッサはDenormalオペランド例外を通知します。Denormalオペランド例外のフラグ(DE)bitとマスク(DM)bitは、それぞれMXCSRレジスタのbit1とbit8です。
CVTSI2PD、CVTPD2PD、CVTPD2PI、CVTDQ2PD、CVTPD2DQ、CVTSD2DQ、CVTSI2SD、CVTSD2SI、CVTTSD2SI、CVTPI2PS、CVTPS2PI、CVTTPS2PI、CVTSS2SI、CVTTSS2SI、CVTSI2SS、CVTDQ2PS、CVTPS2DQ、CVTTPS2DQ変換命令は、denormal例外を通知しません。RCPSS、RCPPS、RSQRTSS、RSQRTPS命令は、いかなる種類の浮動小数点例外も通知しません。
MXCSRレジスタのdenormals-are-zeroフラグ(bit 6)は、denormalオペランド例外を処理する追加のオプションを提供します。このフラグが設定されていると、ソースオペランドの符号を使用してdenormalソースオペランドが自動的に0に変換されます(Section 10.2.3.4を参照)。denormalオペランド例外はflush-to-zeroモードの影響を受けません。
denormal例外の詳細については、Section 4.9.1.2を参照してください。
マスクされていない例外の処理については、Section 11.5.4を参照してください。

##### 11.5.2.3 Divide-By-Zero Exception (#Z)
DIVPS命令、DIVSS命令、DIVPD命令またはDIVSD命令が有限でゼロでないオペランドを0で除算しようとすると、プロセッサはゼロ除算例外を報告します。ゼロ除算のフラグ(ZE)およびマスク(ZM) 例外はMXCSRレジスタのbit 2とbit 9です。
ゼロ除算例外の詳細については、Section 4.9.1.3を参照してください。
マスクされていない例外の処理については、Section 11.5.4を参照してください。
ゼロ除算例外は、単一命令境界でのflush-to-zeroモードの影響を受けません。
DAZはIEEE例外のシグナリングのルールには影響しませんが、DAZ = 1の場合、正規化入力の操作が異なる結果になることがあります。結果として、DAZは、denormal入力を伴う所定の演算で観測されるときに、ゼロ除算例外を含む浮動小数点例外に影響を与えることができます。

##### 11.5.2.4 Numeric Overflow Exception (#O)
プロセッサは、算術命令の丸められた結果が宛先オペランドに収まる最大許容有限値を超えると、数値オーバーフロー例外を報告します。この例外は、ADDPS、ADDSD、ADDSD、SUBPS、SUBSS、SUBPD、SUBSD、MULPS、MULSD、MULDS、DIVPS、DIVSS、DIVPD、DIVSD、CVTPD2PS、CVTSD2SS、ADDSUBPD、ADDSUBPS、HADDPD、HADDPS 、HSUBPD、HSUBPS命令で生成されます。 数値オーバーフロー例外のフラグ(OE)bitとマスク(OM)bitは、それぞれMXCSRレジスタのbit 3とbit 10です。
数値オーバーフロー例外の詳細は、Section 4.9.1.4を参照してください。マスクされていない例外の処理については、Section 11.5.4を参照してください。
数値のオーバーフロー例外は、flush-to-zeroモードまたはdenormals-are-zeroモードの影響を受けません。

##### 11.5.2.5 Numeric Underflow Exception (#U)
プロセッサは、無制限の指数を持つ算術命令の丸められた結果の大きさが、宛先オペランドに収まる最小の正規化された有限値より小さく、数値アンダーフロー例外がマスクされていないときは、数値のアンダーフロー例外を報告します。数値のアンダーフロー例外がマスクされている場合は、アンダーフローが報告される前に、アンダーフローと不正確な結果の両方の条件を検出する必要があります。
この例外は、ADDPS、ADDSD、ADDSD、SUBPS、SUBSS、SUBPD、SUBSD、MULPS、MULSD、MULDS、DIVPS、DIVSS、DIVPD、DIVSD、CVTPD2PS、CVTSD2SS、ADDSUBPD、ADDSUBPS、HADDPD、HADDPS 、HSUBPD、およびHSUBPS命令で生成されます。アンダーフロー例外のフラグ(UE)bitとマスク(UM)bitは、それぞれMXCSRレジスタのbit 4とbit 11です。
MXCSRレジスタのflush-to-zeroフラグ(bit 15)は、数値のアンダーフロー例外を処理するための追加オプションを提供します。このフラグが設定されていて数値のアンダーフロー例外がマスクされている場合、小さな結果は真の結果の符号付きでゼロとして返されます(Section 10.2.3.3を参照)。
アンダーフローは、IEEE Standard 754-2008に記述されているように、ゼロ以外の小さな結果が検出されたときに発生します(アンダーフロー例外がマスクされていれば結果も不正確でなければなりません)。DAZはIEEE例外のシグナリングのルールには影響しませんが、DAZ = 1の場合、正規化入力の操作が異なる結果になることがあります。結果として、DAZは、denormal入力を伴う所定の演算に対して観測されるとき、浮動小数点例外(アンダーフロー例外を含む)に影響を与える可能性があります。
数値アンダーフロー例外の詳細については、Section 4.9.1.5を参照してください。マスクされていない例外の処理については、Section 11.5.4を参照してください。

#### 11.5.3 Generating SIMD Floating-Point Exceptions
プロセッサは、パックされた浮動小数点命令またはスカラ浮動小数点命令を実行すると、2つのシーケンシャルステップを使用してSIMD浮動小数点例外条件を検索し、レポートします。

1. 計算前の例外条件(無効オペランド、ゼロ除算、denormalオペランド)を検索、レポート、処理します。
2. 計算後の例外条件(数値オーバーフロー、数値アンダーフロー、不正確な結果)を検索、レポート、処理します。

計算前と計算後の両方の例外がマスクされていない場合、プロセッサはSSE、SSE2またはSSE3命令の実行中にSIMD浮動小数点例外(#XM)を2回生成することができます。計算前の例外、および計算後の例外を検出したときに発生します。

##### 11.5.3.1 Handling Masked Exceptions
すべての例外がマスクされている場合、プロセッサは、マスクされた結果(またはパックされたオペランドの結果)を宛先オペランドに配置し、プログラムの実行を継続することによって、検出した例外を処理します。マスクされた結果は、検出された例外条件に応じて、丸められた正規化された値、符号付き無限大、denormal有限個数、ゼロ、QNaN浮動小数点不定、またはQNaNになります。ほとんどの場合、MXCSRの対応する例外フラグbitも設定されます。例外フラグがセットされていない1つの状況は、アンダーフロー条件が検出され、不正確な結果を伴わない場合です。
パックされた浮動小数点オペランドで動作する場合、プロセッサは、各サブオペランド計算に対してマスク結果を返し、各計算に対して別々の内部例外フラグセットを設定します。その後、内部例外フラグ設定のORを実行し、OR演算の結果に従ってMXCSRレジスタに例外フラグを設定します。
たとえば、図11-9にMULPS命令の結果を示します。この例では、すべてのSIMD浮動小数点例外がマスクされています。サブオペランドX0とY0の乗算に先立ち、非正規化例外条件が検出され、X1とY1の乗算に対して例外条件が検出されず、X2とY2の乗算に対して数値オーバーフロー例外条件が検出され、サブオペランドX3とY3の乗算の前にdenormal例外が検出されます。denormal例外がマスクされるので、プロセッサは、乗算の結果を宛先オペランドに渡す(X0およびY0)および(X3およびY3)の乗算におけるdenormal元値を使用します。denormalオペランドの場合、X0とY0の計算結果は正規化された有限値であり、例外は検出されません。しかし、X3とY3の計算では、小さくて不正確な結果が得られます。これにより、対応する内部数値アンダーフローフラグと不正確結果例外フラグが設定されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/a4b73eee-efc6-10be-b0d9-4f88352e8def.png)

X2とY2の乗算の場合、プロセッサは、宛先オペランドに浮動小数点∞を格納し、対応する内部サブオペランドの数値オーバーフローフラグを設定します。X1とY1の乗算の結果は、宛先オペランドに渡され、内部サブオペランド例外フラグはセットされません。計算に続いて、denormalオペランド、数値アンダーフロー、不正確結果、および数値オーバフローに対する個々のサブオペランド例外フラグはORであり、対応するフラグはMXCSRレジスタにセットされます。
この計算の最終的な結果は次のとおりです。

- X0とY0の乗算は正規化された有限の結果を生成
- X1とY1の乗算は正規化された有限の結果を生成
- X2とY2の乗算は浮動小数点∞の結果を生成
- X3とY3の乗算は、小さく、不正確で有限の結果を生成
- denormalオペランド、数値アンダーフロー、数値アンダーフロー、および不正確結果フラグがMXCSRレジスタに設定

##### 11.5.3.2 Handling Unmasked Exceptions
(省略)

##### 11.5.3.3 Handling Combinations of Masked and Unmasked Exceptions
(省略)

#### 11.5.4 Handling SIMD Floating-Point Exceptions in Software
(省略)

#### 11.5.5 Interaction of SIMD and x87 FPU Floating-Point Exceptions
SIMD浮動小数点例外は、x87 FPU浮動小数点例外から独立して生成されます。SIMD浮動小数点例外は、FERR#ピンのアサートを引き起こしません(CR0.NE [bit 5]の値に依存しない)。
IGNNE#ピンのアサーションとディアサーションは無視されます。
(以下省略)

### 11.6 WRITING APPLICATIONS WITH SSE/SSE2 EXTENSIONS
以下のセクションでは、SSEおよびSSE2拡張を使用するアプリケーションプログラムおよびOSコードを記述するためのガイドラインを示します。SSE拡張とSSE2拡張は同じ状態を共有し、コンパニオン操作を実行するため、これらのガイドラインは両方の拡張機能セットに適用されます。
3AのChapter 13では、SSE/SSE2/SSE3拡張を使用するコードを記述する際のコンテキスト切り替えのためのプロセッサとその他のOSに関する考慮事項について説明しています。

#### 11.6.1 General Guidelines for Using SSE/SSE2 Extensions
次のガイドラインでは、SSEおよびSSE2拡張で使用可能なパフォーマンスの向上を最大限に活用する方法について説明します。

- プロセッサーがSSEおよびSSE2拡張機能をサポートしていることを確認します。
- 効率的なメモリ使用のために、データを適切に整列させた状態に保つために、スタックとデータの整列手法を使用します。
- ご使用のOSがSSEおよびSSE2拡張をサポートしていることを確認してください。(SSE拡張のOSサポートは、SSE2拡張のサポートを意味し、逆も同様です)。
- SSEおよびSSE2拡張で提供されるnon-temporal store命令を使用します。
- インテルPentium4最適化マニュアルに記載されている最適化とスケジューリングの手法を使用します。

#### 11.6.2 Checking for SSE/SSE2 Support
アプリケーションがSSEおよび/またはSSE2拡張を使用する前に、それらがプロセッサ上に存在することを確認する必要があります。

1. プロセッサがCPUID命令をサポートしていることを確認します。EFLAGSレジスタのbit 21は、プロセッサのCPUID命令のサポートをチェックするために使用できます。
2. プロセッサがSSEおよび/またはSSE2拡張をサポートしていることを確認します(CPUID.01H：EDX.SSE [bit 25] = 1および/またはCPUID.01H：EDX.SSE2 [bit 26] = 1)。
OSは、アプリケーションがSSEおよび/またはSSE2拡張機能を使用する前に、SSE状態を処理するためのシステムレベルのサポートを提供する必要があります(3AのChapter 13参照)。
プロセッサがサポートされていないSSEまたはSSE2命令を実行しようとすると、プロセッサは無効オペコード例外(#UD)を生成します。OSがSSEに対する適切なシステムレベルのサポートを提供していない場合、SSEまたはSSE2命令を実行すると#UDも生成されます。

#### 11.6.3 Checking for the DAZ Flag in the MXCSR Register
MXCSRレジスタのdenormals-are-zeroフラグは、いくつかの初期のステッピングを除いて、ほとんどのPentium 4プロセッサとインテルXeonプロセッサで使用できます。MXCSRレジスタにDAZフラグが存在するかどうかを確認するには、次のようにします。

1. メモリに512ByteのFXSAVE領域を確立します。
2. FXSAVE領域をすべて0にクリアします。
3. 解除したFXSAVE領域の先頭Byteのアドレスをソースオペランドとして使用して、FXSAVE命令を実行します。3のChapter 3を参照してください。
4. FXSAVEイメージ(Byte 28-31)のMXCSR_MASKフィールドの値を確認します。
   - MXCSR_MASKフィールドの値が00000000Hの場合、DAZフラグとdenormals-are-zeroモードはサポートされていません。
   - MXCSR_MASKフィールドの値がゼロではなく、bit 6がセットされている場合、DAZフラグとdenormals-are-zeroモードがサポートされます。

DAZフラグがサポートされていない場合、それは予約bitであり、1を書き込むと一般保護例外(#GP)が発生します。MXCSRレジスタへの書き込み時に一般保護例外を防止するための一般的なガイドラインについては、Section 11.6.6を参照してください。

#### 11.6.4 Initialization of SSE/SSE2 Extensions
SSE状態とSSE2状態はXMMレジスタとMXCSRレジスタに含まれます。ハードウェアがリセットされると、この状態は次のように初期化されます(表11-2を参照)。

- すべてのSIMD浮動小数点例外はマスクされます(MXCSRレジスタのbit 7-12は1に設定されます)。
- すべてのSIMD浮動小数点例外フラグがクリアされます(MXCSRレジスタのbit 0-5は0に設定されます)。
- 丸め制御は最も近い値に設定されます(MXCSRレジスタのbit 13-14は00Bに設定されます)。
- flush-to-zeroモードは無効化されます(MXCSRレジスタのbit 15は0に設定されています)。
- denormals-are-zeroモードは無効化されます(MXCSRレジスタのbit 6は0に設定されます)。denormals-are-zeroモードがサポートされていない場合、このbitは予約されており、初期化時に0に設定されます。
- 各XMMレジスタはクリアされます(すべてゼロに設定されます)。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/00fcb816-461d-9378-2801-f5ac50f344ac.png)

INIT#ピンをアサートしてプロセッサをリセットすると、SSEおよびSSE2の状態は変更されません。

#### 11.6.5 Saving and Restoring the SSE/SSE2 State
FXSAVE命令は、x87 FPU、MMX、SSE、SSE2の状態(8個のXMMレジスタとMXCSRレジスタの内容を含む)を512Byteのメモリブロックに保存します。FXRSTOR命令は、保存されたSSEおよびSSE2状態をメモリから復元します。512Byteの状態ブロックのレイアウトについては、2AのChapter3を参照してください。
FXSAVEとFXRSTORは、SSEとSSE2の状態の保存と復元に加えて、x87 FPUの状態を保存して復元します(MMXレジスタはx87 FPUデータレジスタにエイリアスされるため、MMX状態の保存と復元が含まれます)。コード効率を高めるには、次の状況で、FSAVE、FNSAVEおよびFRSTOR命令の代わりにFXSAVEおよびFXRSTOR命令を使用することをお勧めします。

- マルチタスク環境でコンテキストを切り替えるとき
- 割り込みと例外ハンドラから呼び出しあるいはリターンの間

コードがx87 FPUとMMXテクノロジの計算(コンテキストスイッチまたは割り込みまたは例外の呼び出しなし)間で切り替わる状況では、FSAVE/FNSAVEおよびFRSTOR命令はFXSAVEおよびFXRSTOR命令よりも効率的です。

#### 11.6.6 Guidelines for Writing to the MXCSR Register
MXCSRにはいくつかの予約bitがあり、これらのbitのいずれかに1を書き込もうとすると、一般保護例外(#GP)が生成されます。 ソフトウェアがこれらの予約bitを識別できるように、MXCSR_MASK値が提供されます。ソフトウェアは、このマスク値を次のように決定できます。

1. メモリに512ByteのFXSAVE領域を確立します。
2. FXSAVE領域をすべて0にクリアします。
3. 解除したFXSAVE領域の先頭Byteのアドレスをソースオペランドとして使用して、FXSAVE命令を実行します。FXSAVEイメージとFXSAVEイメージのレイアウトについては、2AのChapter3章を参照してください。
4. FXSAVEイメージ(Byte 28-31)のMXCSR_MASKフィールドの値を確認します。
   - MXCSR_MASKフィールドの値が00000000Hの場合、MXCSR_MASK値はデフォルト値の0000FFBFHになります。この値は、MXCSRレジスタのbit 6が予約されていることを示します。この設定は、プロセッサでゼロ以外のモードがサポートされていないことを示します。
   - MXCSR_MASKフィールドの値がゼロでない場合は、MXCSR_MASK値をMXCSR_MASKとして使用する必要があります。
   
MXCSR_MASK値の0に設定されたすべてのbitは、MXCSRレジスタの予約bitを示します。したがって、MXCSR_MASK値がMXCSRレジスタに書き込まれる値とANDされた場合、結果の値はすべての予約bitが0に設定されていることが保証され、汎用保護例外が発生する可能性がなくなります。値はMXCSRレジスタに書き込まれます。
たとえば、00000000HがFXSAVEイメージに返されるときのデフォルトのMXCSR_MASK値は0000FFBFHです。ソフトウェアANDがMXCSRに書き込まれる値が0000FFBFHで登録されている場合、結果のbit 6(DAZフラグ)は0に設定されます。これは、サポートしていないプロセッサで一般保護例外を防止するために必要な設定です denormals-are-zeroモードです。
一般保護例外を防止するために、MXCSR_MASK値は、次の状況でMXCSRレジスタに書き込まれる値とのANDをとる必要があります。

- アプリケーションプログラムからパラメータを受け取り、その値をMXCSRレジスタに書き込むOSルーチン(FXRSTOR命令またはLDMXCSR命令のいずれか)
- MXCSRレジスタに書き込みを行い、いくつかの異なるIA-32プロセッサ上で堅牢に動作する必要のあるアプリケーションプログラム

1に設定されたMXCSR_MASK値のすべてのbitがMXCSRレジスタによってサポートされている機能を示していることに注意してください。プロセッサ機能を識別するための機能フラグとして扱うことができます。

#### 11.6.7 Interaction of SSE/SSE2 Instructions with x87 FPU and MMX Instructions
同じコードモジュール内でSSE、SSE2、MMX、およびx87 FPU命令を実行する場合、またはこれらの命令を含むコードモジュールを混在させる場合に、XMMレジスタとx87 FPUおよびMMXレジスタは別個の実行環境を表します。

- 制限のない64bit SIMD整数またはx87 FPU命令を使用して同じ命令ストリーム内のXMMレジスタ(パックされた浮動小数点命令、スカラ浮動小数点命令および128bit SIMD整数命令など)でのみ動作するSSEおよびSSE2命令。たとえば、アプリケーションでは、パックされた浮動小数点命令とスカラ浮動小数点命令を使用してXMMレジスタで浮動小数点演算の大部分を実行できます。同時に、x87 FPUを使用して三角関数やその他の高等計算を実行できます。同様に、アプリケーションは、パックされた64bitおよび128bitのSIMD整数演算を制限なしで一緒に実行できます。
- MMXレジスタで動作するSSEおよびSSE2命令(CVTPS2PI、CVTTPS2PI、CVTPI2PS、CVTPD2PI、CVTTPD2PI、CVTPI2PD、MOVDQ2Q、MOVQ2DQ、PADDQ、およびPSUBQ命令など)も、64bitただし、SIMD整数命令またはx87 FPU命令の場合、MMXテクノロジとx87 FPU命令の同時使用に関する制限が適用されます。
  - x87 FPUからMMXテクノロジ命令、またはMMXレジスタで動作するSSE命令またはSSE2命令への移行に先立って、x87 FPUの状態を保存する必要があります。
  - MMXテクノロジ命令から、またはMMXレジスタからx87 FPU命令へと動作するSSE命令またはSSE2命令からEMMS命令を実行する前に移行する必要があります。

#### 11.6.8 Compatibility of SIMD and x87 FPU Floating-Point Data Types
SSEおよびSSE2拡張は、x87 FPUが動作するのと同じ単精度および倍精度浮動小数点データ型で動作します。しかし、これらのデータ型で動作する場合、SSE拡張とSSE2拡張は、倍精度浮動小数点形式から倍精度拡張浮動小数点形式に拡張されたx87 FPUとは異なり、ネイティブ形式(単精度または倍精度)で動作します。計算結果をメモリに書き込む前に計算を実行し、結果を単精度または倍精度の形式に丸めます。 x87 FPUはより高い精度のフォーマットで動作し、その結果をより低い精度のフォーマットに丸めますので、返されるものと同じ単精度または倍精度の浮動小数点値で同じ操作を実行すると、わずかに異なる結果を返すことがあります SSEとSSE2の拡張によって。 この差は、仮数部の最下位bitにのみ発生します。

#### 11.6.9 Mixing Packed and Scalar Floating-Point and 128-Bit SIMD Integer Instructions and Data
SSE拡張とSSE2拡張は、パックされたあるいはスカラ浮動小数点データ型と128bitSIMD整数データ型で型付き操作を定義しますが、IA-32プロセッサーはこの型付けをアーキテクチャレベルで強制しません。これらはマイクロアーキテクチャレベルでのみそれを実施します。したがって、Pentium 4またはIntel Xeonプロセッサが、パックされたあるいはスカラー浮動小数点オペランドまたは128bitのパックされた整数オペランドをメモリからXMMレジスタにロードするとき、命令に指定されたデータ型がロードされている実際のデータ型と一致しているかチェックしません。同様に、プロセッサがXMMレジスタ内のデータに対して算術演算を実行する場合、プロセッサは、動作中のデータが命令で指定されたデータ型と一致するかどうかをチェックしません。
一般的な規則として、SIMD浮動小数点および整数データ型のデータ型はアーキテクチャレベルで強制されないため、プログラマ、アセンブラ、またはコンパイラがコードでデータ型を強制することは責任があります。正しいデータ型を指定しないと、予期しない結果を返す計算につながる可能性があります。
たとえば、次のコードサンプルでは、2つのパックされた単精度浮動小数点オペランドがメモリからXMMレジスタに移動されます(MOVAPS命令を使用)。オペランドに対して倍精度のパックされた加算演算(ADDPD命令を使用)が実行されます。

```
movaps xmm0, [eax] ; EAX register contains pointer to packed
                   ; single-precision floating-point operand
movaps xmm1, [ebx]
addpd  xmm0, xmm1
```

数値オーバーフロー(#O)や無効操作(#I)などのSIMD浮動小数点例外が発生する可能性がありますが、問題の実際のソース(矛盾するデータ型)は検出されません。
実行中の命令の型付けと矛盾するデータ型を含むオペランド上で動作する能力は、いくつかの有効な動作が実行されることを可能にする。たとえば、次の命令は、パックされた倍精度浮動小数点オペランドをメモリからレジスタXMM0にロードし、マスクを使用してXMM1をロードします。XORPDを使用して、2つのパックされた値の符号bitをレジスタXMM0にトグルします。

```
movapd xmm0, [eax] ; EAX register contains pointer to packed
                   ; double-precision floating-point operand
movaps xmm1, [ebx] ; EBX register contains pointer to packed
				   ; double-precision floating-point mask
xorpd  xmm0, xmm1  ; XOR operation toggles sign bits using
                   ; the mask in xmm1
```

この例では、XORPSまたはPXORをXORPDの代わりに使用して、同じ正しい結果を得ることができます。しかし、オペランドデータ型と命令データ型との間の型の不一致により、マイクロアーキテクチャレベルでの命令の実装のために待ち時間のペナルティが発生します。
レイテンシ違反は、間違ったタイプの移動命令を使用することによっても発生する可能性があります。たとえば、MOVAPSとMOVAPDの両方を使用して、パックされた単精度オペランドをメモリからXMMレジスタに移動することができます。ただし、MOVAPDを使用すると、正しくタイプされた命令がレジスタ内のデータを使用しようとすると、レイテンシのペナルティが発生します。
XMMレジスタからメモリにデータを移動するとき、これらのレイテンシペナルティが発生しないことに注意してください。

#### 11.6.10 Interfacing with SSE/SSE2 Procedures and Functions
SSEおよびSSE2拡張はXMMレジスタへの直接アクセスを可能にします。つまり、汎用レジスタ(EAX、EBXなど)の使用に適用されるプロシージャと関数の間の既存のインタフェース規約はすべて、XMMレジスタの使用にも適用されます。

##### 11.6.10.1 Passing Parameters in XMM Registers
XMMレジスタの状態は、プロシージャ(または関数)の境界を越えて保持されます。XMMレジスタを使用して、あるプロシージャから別のプロシージャにパラメータを渡すことができます。

##### 11.6.10.2 Saving XMM Register State on a Procedure or Function Call
XMMレジスタの状態は、FXSAVE命令または移動命令の2つの方法で保存できます。FXSAVEは、すべてのXMMレジスタの状態を保存します(MXCSRおよびx87 FPUレジスタの状態とともに)。この命令は、通常、タスクスイッチなどの実行環境のコンテキストにおける大きな変更に使用されます。FXRSTORは、FXSAVEで格納されたXMM、MXCSR、およびx87 FPUレジスタを復元します。
XMMレジスタのみを保存する必要がある場合、または選択したXMMレジスタを保存する必要がある場合は、MOVAPS、MOVUPS、MOVSD、MOVAPD、MOVSD、MOVSD、MOVDQA、MOVDQUの各命令を使用できます。
これらの命令は、XMMレジスタの内容を復元するためにも使用できます。XMMレジスタをメモリに保存するとき、またはメモリからXMMレジスタをロードするときにパフォーマンスが低下しないようにするには、適切に入力された移動命令を使用してください。
移動命令は、XMMレジスタの内容をスタックに保存するためにも使用できます。ここで、(ESPレジスタ内の)スタックポインタは、スタック内の次に使用可能なByteのメモリアドレスとして使用できます。スタックポインタは、(PUSHの場合のように)移動命令を使用すると自動的にインクリメントされないことに注意してください。
XMMレジスタの内容をスタックにセーブする移動命令プロシージャは、ESPレジスタの値を16だけ減分する責任があります。同様に、スタックからXMMレジスタをロードする移動命令プロシージャもESPをインクリメントする必要がありますXMMレジスタの内容を移動するときのパフォーマンスの低下を避けるには、適切に入力された移動命令を使用します。
LDMXCSRおよびSTMXCSR命令を使用して、プロシージャ呼び出しおよび復帰時にMXCSRレジスターの内容をそれぞれ保管および復元します。

##### 11.6.10.3 Caller-Save Recommendation for Procedure and Function Calls
SSEまたはSSE2コードからプロシージャ(または関数)コールを作成する場合は、呼び出し元プロシージャの状態を保存するために、呼び出し元保存規約が推奨されます。この規約を使用すると、内容がプロシージャコールでそのまま残っていなければならないレジスタは、コールを実行する前に呼び出しプロシージャによってメモリに格納されなければなりません。
呼び出し元保存の規則を使用する主な理由は、パフォーマンスの低下を防ぐためです。 XMMレジスタには、パックされたまたはスカラ倍精度浮動小数点、および128bit パックされた整数データ型を含めることができます。呼び出されたプロシージャは、呼び出し後にXMMレジスタのデータ型を知る方法がありません。XMMレジスタの内容をメモリに格納するか、またはメモリからXMMレジスタの内容を復元するために、正しく型付けされた移動命令を使用することは考えにくいです。
Section 11.6.9で説明しているように、XMMレジスタとの間で移動するデータの型と一致しない移動命令を実行すると、正しい命令が実行されますが待ち時間長くなる可能性があります。

#### 11.6.11 Updating Existing MMX Technology Routines Using 128-Bit SIMD Integer Instructions
(省略)

#### 11.6.12 Branching on Arithmetic Operations
SSEまたはSSE2状態には条件コードはありません。パックされたデータ比較命令は、マスクを生成し、その後マスクを整数レジスタに転送することができます。次のコードシーケンスは、SSE2算術演算の結果に基づいて条件分岐を実行する方法の例を示しています。

```
cmppd    XMM0, XMM1    ; generates a mask in XMM0	 
movmskpd EAX, XMM0	   ; moves a 2 bit mask to eax	 
test     EAX, 0		   ; compare with desired result
jne      BRANCH TARGET
```

COMISDおよびUCOMISD命令は、スカラ比較の結果としてEFLAGSを更新します。COMISD/UCOMISDの直後に条件分岐をスケジュールすることができます。

#### 11.6.13 Cacheability Hint Instructions
SSEおよびSSE2キャッシュ制御命令は、プログラマがデータのプリフェッチ、キャッシング、ロードおよびストアを制御することを可能にします。これらの命令を正しく使用すると、アプリケーションのパフォーマンスが向上します。
プロセッサのスーパースカラマイクロアーキテクチャを効率的に使用するためには、プログラムがプロセッサを停止させるのを避けるために、実行中のプログラムに安定したデータストリームを提供する必要があります。PREFETCHh命令は、実際の使用に先立って、データをプロセッサキャッシュ階層にフェッチすることを可能にすることによって、アプリケーションコードの性能重視のセクションにおけるデータアクセスの待ち時間を最小にします。
PREFETCHh命令は、パフォーマンスに影響を与える可能性がありますが、プログラムのユーザー視覚セマンティクスを変更しません。これらの命令の動作は実装依存です。プログラマは、各IA-32プロセッサの実装ごとにコードを調整する必要があります。PREFETCHh命令を過度に使用すると、メモリ帯域幅が浪費され、パフォーマンスが低下する可能性があります。プリフェッチヒントの使用の詳細については、最適化リファレンスマニュアルのChapter 7を参照してください。
non-temporal store命令(MOVNTI、MOVNTPD、MOVNTPS、MOVNTDQ、MOVNTQ、MASKMOVQ、およびMASKMOVDQU)は、non-temporalなデータをメモリに書き込むときのキャッシュ汚染を最小限に抑えます(Section 10.4.6.1およびSection 10.4.6.2を参照)。それらは、non-temporalなデータがストア操作でプロセッサキャッシュに書き込まれるのを防ぎます。
キャッシュ汚染を減らすことに加えて、弱い順序のメモリタイプの使用は、生産者-消費者関係などの特定のデータ共有関係の下で重要になります。弱い順序のメモリを使用すると、データの組み立てをより効率的に行うことができます。消費者はプロデューサが意図したデータを確実に取得するように注意する必要があります。このように弱い順序ストアによって影響を受ける可能性のある一般的な使用モデルには、次のものがあります。

- 弱い順序のメモリを使用して結果を書き出すライブラリ関数
- 弱い順序付けられた結果を書き込むコンパイラ生成コード
- 手作りのコード

(以下省略)

#### 11.6.14 Effect of Instruction Prefixes on the SSE/SSE2 Instructions
表11-3に、SSEおよびSSE2命令に対する命令プレフィクスの影響を示します。(表11-3は、SSE3のSIMD整数およびSIMD浮動小数点命令にも適用されます)。予測不可能な動作は、ある世代のIA-32プロセッサで予約操作として扱われるプレフィクスから、別の世代 プロセッサに対して生成される無効操作まであります。
命令プリフィックスの詳細については、2AのChapter 2も参照してください。

> SSE/SSE2/SSE3命令の中には、2Byteまたは3Byteの長さのオペコードがあります。3バイトの長さのオペコードは、必須プレフィクス(F2H、F3H、または66H)、0FH、およびオペコードバイトで構成されます。表11-3を参照してください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/7607ff7d-fd84-461e-a2bf-011e3912f9f2.png)

## CHAPTER 12 PROGRAMMING WITH INTEL SSE3, SSSE3, INTEL SSE4 AND INTEL AESNI
この章では、SSE3、SSSE3、SSE4について説明し、これらの拡張機能を使用するアプリケーションプログラムの作成に役立つ情報を提供します。
AESNIおよびPCLMLQDQは、高速ブロック暗号化および暗号化処理を高速化するための命令拡張です。Section 12.13では、これらの説明とAdvanced Encryption Standard(AES)との関係について説明します。

### 12.1 PROGRAMMING ENVIRONMENT AND DATA TYPES
SSE3、SSSE3、SSE4を使用するためのプログラミング環境は、図3-1と図3-2に示したものから変更されていません。
SSE3、SSSE3、SSE4では新しいデータ型は導入されていません。XMMレジスタはパックされた整数データまたは単精度浮動小数点データ、倍精度浮動小数点データに対して操作するために使用されます。
一つのSSE3命令はx87スタイルのプログラミングにx87 FPUを使用します。スレッド同期に汎用レジスタを使用する二つのSSE3命令もあります。MXCSRレジスタはSIMD浮動小数点操作を制御します。ただし、x87FPU制御ワードは、無効なオペランドまたは不正確な結果例外をアンマスクすることを除き、x87 FPU(FISTTP)によって実行されるSSE3命令には影響しません。
SSE4命令はMMXレジスタを使用しません。SSE4.2の多くの命令とSSE4.1命令はXMMレジスタを操作します。

#### 12.1.1 SSE3, SSSE3, SSE4 in 64-Bit Mode and Compatibility Mode
互換モードでは、SSE3, SSSE3, SSE4は保護モードと同様に機能します。64bitモードでは、8つの追加XMMレジスタが利用可能です。XMM8-15はREXプレフィクスを使用してアクセスできます。
(以下省略)

#### 12.1.2 Compatibility of SSE3/SSSE3 with MMX Technology, the x87 FPU Environment, and SSE/SSE2 Extensions
(省略)

#### 12.1.3 Horizontal and Asymmetric Processing
多くのSSE/SSE2/SSE3/SSSE3命令は、垂直計算と呼ばれるモデルを使用してSIMDデータ処理を高速化します。このモデルを使用すると、データフローは入力のデータ要素と出力の間で垂直になります。
図12-1に、SSE3命令ADDSUBPDの非対称処理を示します。図12-2に、SSE3命令HADDPDの水平方向のデータ移動を示します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/1a6714c1-d741-f3e1-6d18-c4192c8311d9.png)


### 12.2 OVERVIEW OF SSE3 INSTRUCTIONS
(省略)

### 12.3 SSE3 INSTRUCTIONS
SSE3命令は次のグループに分かれています。

- x87 FPU命令
  - x87 FPU浮動小数点から整数への変換を改善する1つの命令
- SIMD整数命令
  - 128bitの整列されていないデータの読み込みに特化した1つの命令
- SIMD浮動小数点命令
  - LOAD/MOVE/DUPLICATEパフォーマンスを強化する3つの命令
  - パックされた加算/減算を提供する2つの命令
  - 水平方向の加算/減算を行う4つの命令
- スレッド同期命令
  - マルチスレッドエージェント間の同期を改善する2つの命令
  
#### 12.3.1 x87 FPU Instruction for Integer Conversion
FISTTP命令(x87 FPUストア整数と切り捨て付きpop)はFISTPのように動作しますが、x87 FPU制御Wordに指定されている丸めモードに関係なく、切り捨てを使用します。命令は、スタックの先頭(ST0)を整数に丸めてスタックに変換し、スタックをpopします。
FISTTP命令は、短い整数(Wordまたは16bit)、整数(Dwordまたは32bit)、およびロング整数(64bit)の3つの精度で使用できます。FISTTPを使用することで、アプリケーションで切り捨てが必要なときにFCWを変更する必要がなくなりました。

#### 12.3.2 SIMD Integer Instruction for Specialized 128-bit Unaligned Data Load
LDDQU命令は、キャッシュライン分割を避けるために設計された特別な128bitのアラインメントされていないロードです。16Byteのロードアドレスが16Byte境界にある場合、LDQQUは要求されたByteをロードします。ロードアドレスが16Byteの境界に揃えられていない場合、LDDQUはロード要求の直下の16Byteのアライメントされたアドレスから開始して32Byteのブロックをロードします。 次に、要求された16Byteを抽出します。
この命令は、一部の使用モデルの制限を犠牲にして、128Bitのアライメントされていないメモリアクセスに対して大幅なパフォーマンス向上をもたらします。

#### 12.3.3 SIMD Floating-Point Instructions That Enhance LOAD/MOVE/DUPLICATE Performance
MOVSHDUP命令は128bitをロード/移動し、第2および第4の32bitデータ要素を複製します。

- MOVSHDUP OperandA, OperandB
  - OperandA(128 bit, 4つの要素): $3_a$, $2_a$, $1_a$, $0_a$
  - OperandB(128 bit, 4つの要素): $3_b$, $2_b$, $1_b$, $0_b$
  - Result(OperandAに格納): $3_b$, $3_b$, $1_b$, $1_b$

MOVSLDUP命令は128bitをロード/移動し、第1および第3の32bitデータ要素を複製します。

- MOVSLDUP OperandA, OperandB
  - OperandA(128 bit, 4つの要素): $3_a$, $2_a$, $1_a$, $0_a$
  - OperandB(128 bit, 4つの要素): $3_b$, $2_b$, $1_b$, $0_b$
  - Result(OperandAに格納): $2_b$, $2_b$, $0_b$, $0_b$

MOVDDUP命令は64bitをロード/移動し、ソースから64bitを複製します。

- MOVDDUP OperandA, OperandB
  - OperandA(128 bit, 2つの要素): $1_a$, $0_a$
  - OperandB(64 bit, 1つの要素): $0_b$
  - Result(OperandAに格納): $0_b$, $0_b$

#### 12.3.4 SIMD Floating-Point Instructions Provide Packed Addition/Subtraction
ADDSUBPS命令には、2つの128bitオペランドがあります。命令は、オペランド内の第2および第4の32bitデータ要素の対に対して単精度加算を実行します。第1および第3の対に対して単精度減算を行います。

- ADDSUBPS OperandA, OperandB
  - OperandA(128 bit, 4つの要素): $3_a$, $2_a$, $1_a$, $0_a$
  - OperandB(128 bit, 4つの要素): $3_b$, $2_b$, $1_b$, $0_b$
  - Result(OperandAに格納): $3_a+3_b$, $2_a-2_b$, $1_a+1_b$, $0_a-0_b$

ADDSUBPD命令には、2つの128bitオペランドがあります。命令は、第2の対のQwordに対して倍精度加算を行い、第1の対に対して倍精度減算を実行します。

- ADDSUBPD OperandA, OperandB
  - OperandA(128 bit, 2つの要素): $1_a$ , $0_a$
  - OperandB(128 bit, 2つの要素): $1_b$, $0_b$
  - Result(OperandAに格納): $1_a+1_b$, $0_a-0_b$

#### 12.3.5 SIMD Floating-Point Instructions Provide Horizontal Addition/Subtraction
ほとんどのSIMD命令は垂直方向に動作します。これは、位置iの結果が、両方のオペランドの位置iの要素の関数であることを意味します。水平加減算は水平方向に動作します。これは、同じソースオペランド内の連続するデータ要素を使用して結果を生成することを意味します。
HADDPS命令は、連続するデータ要素に対して単精度加算を実行します。結果の第1のデータ要素は、第1のオペランドの第1および第2の要素を加算することによって得られます。また第2の要素は、第1のオペランドの第3および第4の要素を加算することによって得られ、第3の要素は、第2のオペランドの第1および第2の要素を加算することによって得られ、第4の要素は、第2のオペランドの第3および第4の要素を加算することによって得られます。

- HADDPS OperandA, OperandB
  - OperandA(128 bit, 4つの要素): $3_a$, $2_a$, $1_a$, $0_a$
  - OperandB(128 bit, 4つの要素): $3_b$, $2_b$, $1_b$, $0_b$
  - Result(OperandAに格納): $3_b+2_b$, $1_b+0_b$, $3_a+2_a$, $1_a+0_a$

HSUBPS命令は、連続したデータ要素に対して単精度減算を実行します。

- HSUBPS OperandA, OperandB
  - OperandA(128 bit, 4つの要素): $3_a$, $2_a$, $1_a$, $0_a$
  - OperandB(128 bit, 4つの要素): $3_b$, $2_b$, $1_b$, $0_b$
  - Result(OperandAに格納): $2_b-3_b$, $0_b-1_b$, $2_a-3_a$, $0_a-1_a$

HADDPD命令は、連続するデータ要素に対して倍精度加算を実行します。

- HADDPD OperandA, OperandB
  - OperandA(128 bit, 2つの要素): $1_a$, $0_a$
  - OperandB(128 bit, 2つの要素): $1_b$, $0_b$
  - Result(OperandAに格納): $1_b+0_b$, $1_a+0_a$
  
HSUBPD命令は、連続するデータ要素に対して倍精度減算を実行します。

- HSUBPD OperandA OperandB
  - OperandA(128 bit, 2つの要素): $1_a$, $0_a$
  - OperandB(128 bit, 2つの要素): $1_b$, $0_b$
  - Result (OperandAに格納): $0_b-1_b$, $0_a-1_a$

#### 12.3.6 Two Thread Synchronization Instructions
MONITOR命令は、ライトバックストアを監視するためのアドレス範囲を設定します。MWAITを使用すると、論理プロセッサは、MONITORによって設定されたアドレス範囲にライトバックストアを待つ間に最適化状態に入ることができます。MONITORとMWAITはその入力に汎用レジスタを使用する必要があります。MONITORとMWAITで使用されるレジスタは正しく初期化されなければなりません。これらの命令ではレジスタの内容は変更されません。

### 12.4 WRITING APPLICATIONS WITH SSE3 EXTENSIONS
(省略)

#### 12.4.1 Guidelines for Using SSE3 Extensions
次のガイドラインでは、SSE3拡張機能を使用する利点を最大限に活用する方法について説明します。
- プロセッサがSSE3拡張機能をサポートしていることを確認します。
  - アプリケーションは、OSがSSE3をサポートすることを保証する必要があります。(SSE拡張のOSサポートは、SSE2拡張とSSE3拡張を十分サポートすることを意味します)。
- OSがMONITORとMWAITをサポートしていることを確認します。
- インテル®4およびIA-32アーキテクチャー最適化リファレンスマニュアル(Section 1.4を参照)に記載されている最適化およびスケジューリングの手法を使用します。

#### 12.4.2 Checking for SSE3 Support
アプリケーションがSSE3拡張のSIMDサブセットを使用する前に、アプリケーションはSection 11.6.2に示す手順に従ってください。次に、以下に示す追加手順を使用します。

- プロセッサがSIMDおよびx87 SSE3拡張(CPUID.01Hの場合:ECX.SSE3 [bit 0] = 1)をサポートしていることを確認します。

SSEのアプリケーションサポートを提供するOSであるSSE2は、SSE3にも十分なアプリケーションサポートを提供します。FISTTPを使用するには、SSE3のサポートを確認する必要があります。

1. プロセッサーがMONITORとMWAITをサポートしていることを確認します。 CPUID.01H:ECX.MONITOR [bit 3] = 1の場合、MONITORとMWAITはring 0で使用できます。
2. MONITORが使用する最小および最大の行サイズを照会します。CPUID.05H:EAX.smallest [bit 15:0]、EBX.largest [bits 15:0]を使用してください。値はEAXとEBXのByte数で返されます。
3. MONITORに供給されるメモリアドレス範囲がメモリタイプ要件を満たしていることを確認します。

MONITORおよびMWAITは、効率的なスレッド同期をサポートするシステムソフトウェアを対象としています。詳しくは、3AのChapter 13を参照してください。

#### 12.4.3 Enable FTZ and DAZ for SIMD Floating-Point Computation
MXCSRレジスタのFTZおよびDAZフラグを有効にすると、IEEE Standard 754-1985への厳密な準拠が必要ないSIMD浮動小数点計算が高速化される可能性があります。FTZフラグは、SSEをサポートするIntel 64およびIA-32プロセッサで使用できます。DAZは、Intel 64プロセッサと、SSE/SSE2/SSE3をサポートするほとんどのIA-32プロセッサで使用できます。
ソフトウェアは、DAZの存在を検出し、MXCSRレジスタを変更し、Section 11.6.3からSection 11.6.6で説明した方法に従って状態情報を保存および復元できます。

#### 12.4.4 Programming SSE3 with SSE/SSE2 Extensions
SSE3拡張のSIMD命令は、SIMDアプリケーションのプログラミングにおけるSSE/SSE2の使用を補完するものです。SSE3命令を使用するアプリケーションソフトウェアは、SSE/SSE2命令の可用性もチェックする必要があります。
SSE3のFISTTP命令は、整数への頻繁な浮動小数点変換によってパフォーマンスが制限されるx87スタイルのプログラミングを高速化することを目的としています。これは、x87 FPU制御Wordが頻繁に変更された場合に発生します。
FISTTPを使用すると、x87 FPU制御Wordにアクセスする必要がなくなります。

### 12.5 OVERVIEW OF SSSE3 INSTRUCTIONS
(省略)

### 12.6 SSSE3 INSTRUCTIONS
SSSE3命令には以下が含まれます。

- 水平方向の加算または減算演算を実行する12の命令。
- 絶対値を評価する6つの命令。
- 乗算および加算演算を実行し、ドット積の評価を高速化する2つの命令。
- パックされた整数乗算演算を高速化し、スケーリング付き整数値を生成する2つの命令。
- 第2のシャッフルコントロールオペランドに従って、Byte単位のインプレースシャッフルを実行する2つの命令。
- ソースオペランドの対応する要素の符号が0より小さい場合、宛先オペランドにパックされた整数を無効にする6つの命令。
- 2つのオペランドのコンポジットからのデータを整列させる2つの命令。

これらの命令のオペランドは、Byte、Word、またはDwordサイズのパックされた整数です。オペランドは、MMXレジスタ、XMMレジスタ、またはメモリに64bitまたは128bitのデータとして格納されます。

#### 12.6.1 Horizontal Addition/Subtraction
SSSE3のパックされた浮動小数点水平加算および減算命令と同様に、SSSE3はパックされた整数データにも同様の機能を提供します。符号付きWord、Dwordのデータ要素がサポートされています。符号付きWordの水平加算および減算のための飽和バージョンもサポートされています。PHADDの水平方向のデータ移動を図12-3に示します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/71d61752-ad4b-bdc3-f074-ab4256e45f19.png)

6つの水平加算命令(3つのニーモニックで表される)があります。3つは128bitオペランドで動作し、3つは64bitオペランドで動作します。各データ要素の幅は16bitまたは32bitです。ニーモニックは以下のとおりです。

- PHADDWは、隣接する2つの符号付き16bit整数をソースオペランドと宛先オペランドから水平方向に加算し、符号付き16bit結果を宛先オペランドにパックします。
- PHADDSWは、隣接する2つの符号付き16bit整数をソースオペランドと宛先オペランドから水平方向に加算し、符号付きの飽和16bit結果を宛先オペランドにパックします。
- PHADDDは、ソースオペランドと宛先オペランドから水平に2つの符号付き32ビット整数を加算し、符号付き32ビット結果を宛先オペランドにパックします。

6つの水平減算命令(3つのニーモニックで表される)があります。3つは128bitオペランドで動作し、3つは64bitオペランドで動作します。各データ要素の幅は16bitまたは32bitのいずれかです。

- PHSUBWは、ソースオペランドと宛先オペランドの各ペアの最下位Wordから最上位Wordを減算することによって、16bit符号付き整数の各隣接対に対して水平減算を実行します。符号付き16bit結果はパックされ、宛先オペランドに書き込まれます 。
- PHSUBSWは、ソースオペランドと宛先オペランドの各ペアの最下位WOrdから最上位Wordを減算することによって、16bit符号付き整数の各隣接対に対して水平減算を実行します。符号付き飽和16bit結果はパックされ、 宛先オペランドに書き込まれます。
- PHSUBDは、ソースオペランドと宛先オペランドの各ペアの最下位Dwordから最上位Dwordを減算することによって、32bit符号付き整数の各隣接対に対して水平減算を実行します。符号付き32bit結果はパックされ、宛先オペランドに書き込まれます。

#### 12.6.2 Packed Absolute Values
6つのパックされた絶対値命令(3つのニーモニックで表される)があります。3つは128bitオペランドで動作し、3つは64bitオペランドで動作します。データ要素の幅は8bit、16bitまたは32bitです。ソースオペランドの各データ要素の絶対値は、宛先オペランドにUNSIGNED結果として格納されます。

- PABSBは、各符号付きByteデータ要素の絶対値を計算します。
- PABSWは、符号付き16bitデータ要素の絶対値を計算します。
- PABSDは、各符号付き32bitデータ要素の絶対値を計算します。

#### 12.6.3 Multiply and Add Packed Signed and Unsigned Bytes
1つのニーモニックで表される2つの積和符号付き符号付き符号なしByte命令があります.1つは128bitのオペランドで動作し、もう1つは64bitのオペランドで動作します。乗算は各データのペアごとに実行されます。ソースオペランドのデータ要素は符号付きByte値であり、宛先オペランドの入力データ要素は符号なしByte値です。

- PMADDUBSWは、各符号なしByte値に対応する符号付きByte値を掛けて、中間の16bit符号付き整数を生成します。隣接する各16bit符号付き値のペアが水平方向に加算されます。符号付きで飽和した16bitの結果は宛先オペランドにパックされます。

#### 12.6.4 Packed Multiply High with Round and Scale
round-and-scale命令には、2つのパックされた高マルチround-and-scale命令(1つのニーモニックで表される)があります。 1つは128bitオペランドで動作し、もう1つは64bitオペランドで動作します。

- PMULHRSWは、宛先オペランドからの各符号付き16bit整数をソースオペランドの対応する符号付き16bit整数と垂直に乗算し、中間の符号付き32bit整数を生成します。各中間32bit整数は、最上位18bitに切り捨てられます。丸めは常に、18bitの中間結果の最下位bitに1を加算することによって実行されます。最終結果は、各18bit中間結果の最上位bitのすぐ右にある16bitを選択し、宛先オペランドにパックすることによって得られる。

#### 12.6.5 Packed Shuffle Bytes
1つのニーモニックで表される2つのパックされたシャッフルバイト命令があります.1つは128bitオペランドで動作し、もう1つは64bitオペランドで動作します。シャッフル動作は、ソースオペランドをマスクコントロールとして使用して、宛先オペランドに対してbit毎に実行します。

- PSHUFBは、シャッフルコントロールマスクに従って各Byteを置換します。コントロールマスクの各シャッフルコントロールバイトの最下位3-4bitがシャッフルインデックスを形成します。シャッフルマスクは影響を受けません。シャッフル制御Byteの最上位bit(bit 7)がセットされている場合、定数0が結果Byteに書き込まれます。

#### 12.6.6 Packed Sign
6つのパックされた符号命令(3つのニーモニックで表される)があります.3つは128bitオペランドで動作し、3つは64bitオペランドで動作します。これらの命令の各データ要素の幅は8bit、16bitまたは32bit符号付き整数です。

- PSIGNB/W/Dは、ソースオペランド内の対応するデータ要素の符号がゼロより小さい場合、宛先オペランドの各符号付き整数要素を否定します。

#### 12.6.7 Packed Align Right
パックされた右アライメント命令(ニーモニック1つで表される)が2つあります.1つは128ビットオペランドで動作し、もう1つは64ビットオペランドで動作します。これらの命令は、宛先オペランドとソースオペランドをコンポジットに連結し、 このコンポジットは即時の定数に従う。

- PALIGNRのソースオペランドは、宛先オペランドの後ろに加算され、オペランドの幅の2倍の中間値を形成します。結果は、中間値から、宛先オペランドに、即値で指定されたByteオフセットに右揃えされた128bitまたは64bitの値を選択することによって抽出されます。

### 12.7 WRITING APPLICATIONS WITH SSSE3 EXTENSIONS
(省略)

#### 12.7.1 Guidelines for Using SSSE3 Extensions
次のガイドラインでは、SSSE3拡張機能を使用する利点を最大限に活用する方法について説明します。

- プロセッサがSSSE3拡張機能をサポートしていることを確認します。
- OSがSSE/SSE2/SSE3/SSSE3拡張をサポートしていることを確認します。(SSE拡張のOSサポートは、SSE2、SSE3、SSSE3の十分なサポートを意味します)。
- インテル64およびIA-32アーキテクチャー最適化リファレンスマニュアル(Section 1.4を参照)に記載されている最適化およびスケジューリングの手法を使用します。

#### 12.7.2 Checking for SSSE3 Support
(省略)

### 12.8 SSE3/SSSE3 AND SSE4 EXCEPTIONS
SSE3、SSSE3、SSE4命令は、他のインテル64またはIA-32命令と同じタイプのメモリアクセスおよび非数値例外を生成できます。既存の例外ハンドラは、通常、コード変更なしでこれらの例外を処理します。
FISTTPは浮動小数点例外を生成できます。SSE3命令の中には、SIMD浮動小数点例外を生成するものもあります。

#### 12.8.1 Device Not Available (DNA) Exceptions
SSE3、SSSE3、SSE4は、プロセッサがCR0.TS [bit 3] = 1のときにプロセッサがSSE3命令を実行しようとするとDNA例外(#NM)を引き起こします。CPUID.01H:ECX.SSE3 [bit 0] = 0の場合、 SSE3拡張の実行は、CR0.TS [bit 3]の状態にかかわらず無効なオペコード違反を引き起こします。
同様に、CPUID.01H:ECX.SSSE3 [bit 9] = 0を報告するプロセッサでSSSE3命令を実行しようとすると、CR0.TS [bit 3]の状態に関係なく無効なオペコード違反が発生します。CPUID.01H:ECX.SSE4_1 [bit 19] = 0を報告するプロセッサ上でSSE4.1命令を実行しようとすると、CR0.TS [bit 3]の状態にかかわらず無効なオペコード違反が発生します。
CPUID.01H：ECX.SSSE3 [bit 20] = 0を報告するプロセッサ上のSSE4.2でPCMPGTQまたは4つの文字列処理命令のいずれかを実行しようとすると、CR0.TS [bit 3]の状態に関係なく無効なオペコード違反が発生します。CRC32とPOPCNTは#NMを引き起こしません。

#### 12.8.2 Numeric Error flag and IGNNE#
ほとんどのSSE3命令はCR0.NE [bit 5] (常に設定されているかのように扱います)とIGNNE#ピンを無視します。1つの例外を除いて、すべてエラー報告のために例外19(#XM)ソフトウェア例外を使用します。例外はFISTTPです。他のx87-FP命令のように動作します。
SSSE3命令はCR0.NE [bit 5] (常に設定されているかのように扱います)とIGNNE#ピンを無視します。
SSSE3命令では浮動小数点エラーは発生しません。SSE4.1の浮動小数点数値エラーについては、Section 12.8.4を参照してください。SSE4.2命令は浮動小数点エラーを発生させません。

#### 12.8.3 Emulation
CR0.EMはいくつかのソフトウェアでx87浮動小数点命令をエミュレートするために使用され、CR0.EM [bit 2]はSSE、SSE2、SSE3、SSSE3、SSE4のエミュレーションには使用できません。SSE3、SSSE3、SSE4命令がCR0.EM [bit 2]がセットされて実行されると、デバイス使用不可例外(INT 7)の代わりに無効なオペコード例外(INT 6)が生成されます。

#### 12.8.4 IEEE 754 Compliance of SSE4.1 Floating-Point Instructions
浮動小数点演算を実行する6つのSSE4.1命令は次のとおりです。

- DPPS
- DPPD
- ROUNDPS
- ROUNDPD
- ROUNDSS
- ROUNDSD

Dot積の動作はIEEE-754で規定されていません。FTZもDAZも有効になっていない場合、ドット積命令は、入力NaNの処理が実装固有であることを除いて(各段で丸められた)IEEE-754の乗算と加算のシーケンスに似ています(出力に少なくとも1つのNaN)。入力選択フィールド(bit imm8 [4:7]）は、入力要素を最初の乗算の前に+0.0fに強制し、それ以外の場合に生成される入力例外を抑止します。
例外ハンドラの便宜のために、DPPSまたはDPPDから通知された例外はすべて宛先を変更しないままにします。
丸め演算は無効で精度が高い信号です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/76d2c5a7-adfc-b00a-968b-387a013e63ab.png)

(以下省略)

### 12.9 SSE4 OVERVIEW
SSE4は、SSE4.1とSSE4.2という2つの拡張機能を備えています。SSE4.1は、メディア、画像、3Dワークロードのパフォーマンスを向上させることを目標としています。SE4.1では、コンパイラのベクトル化を改善し、パックされたWord計算のサポートを大幅に向上させる命令が追加されています。このテクノロジは、キャッシング不可能なWCメモリタイプから読み取るときのメモリスループットを向上させるヒントも提供します。
47のSSE4.1命令には以下が含まれます。

- 2つの命令がパックされたWord乗算を実行。
- 2つの命令が入出力選択付き浮動小数点ドット積を実行。
- 1つの命令がストリーミングヒントでロードを実行。
- 6つの命令は、パックブレンドを簡略化。
- パックされた整数MIN/MAXのサポートを拡張する8つの命令。
- 4つの命令は、選択可能な丸めモードと精度例外オーバーライドを使用して浮動小数点の丸めをサポート。
- 7つの命令が、XMMレジスタからのデータ挿入および抽出を改善。
- パックされた整数フォーマット変換(符号拡張とゼロ拡張)を改善する12の命令。
- 小さなブロックサイズのSAD(sum absolute difference)の生成が改善する命令。
- 水平方向の検索操作を支援する命令。
- マスクされた比較を改善する命令。
- パックされたQword等価比較を追加する命令。
- 符号なし飽和を伴うDwordパッキングを追加する命令。

XMMレジスタで動作するSSE4.2命令は、次の領域でパフォーマンスを向上させます。

- SIMD技術を利用できる文字列とテキスト処理
- SSE4.1で128bit整数SIMD機能の能力を強化するSIMD整数命令。

### 12.10 SSE4.1 INSTRUCTION SET

#### 12.10.1 Dword Multiply Instructions
SSE4.1では、ベクトル化を支援する2つのDword乗算命令が追加されています。それらは同時に4つの32bit*32bitの乗算を可能にします。PMULLDは結果の下位32bitを返し、PMULDQは64bitの符号付き結果を返します。これは最も一般的な整数の乗算演算を表します。表12-2を参照してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/6c5d1972-2abd-62f3-9bb7-07107b917ba2.png)


#### 12.10.2 Floating-Point Dot Product Instructions
SSE4.1では、倍精度(2要素まで、DPPD)と単精度ドット積(4要素まで、DPPS)の2つの命令が追加されています。
これらのドット積命令には、一般に柔軟性を向上させるソース選択および宛先ブロードキャストが含まれています。たとえば、2,3、または4要素のドット積には単一のDPPS命令を使用できます。

#### 12.10.3 Streaming Load Hint Instruction
歴史的に、WCメモリタイプ領域のCPU読み取りアクセスは、キャッシュ可能メモリへのアクセスよりもスループットが大幅に低くなっています。
SSE4.1のストリーミングロード命令であるMOVNTDQAは、WCメモリタイプ(ストリーミングライン)の整列された64Byte領域内の隣接する16Byteのアイテムをフェッチして小さな一時バッファセット(ストリーミングロードバッファ)に保持するnon-temporal hintを提供します。同じストリーミングライン内の他の整列された16Byte項目への後続のストリーミング負荷は、ストリーミングロードバッファから満足され、スループットを改善することができます。
プログラマは、WCメモリからのMOVNTDQAストリーミングロードの効率を改善するために、以下のプラクティスを使用することが推奨されます。

- ストリーミングロードは16Byteにアライメントされるべきです。
- 小さなストリーミングロードバッファを有効に使用するために、同じストリーミングキャッシュラインのストリーミングロードを一時的にグループ化します。同じストリーミングラインへのロードが過度に離れていると、ストリーミングラインがメモリから再フェッチされる可能性があります。
- 最大でいくつかのストリーミングラインからストリーミングロードを一時的にグループ化します。ストリーミングロードバッファの数は少ないため、適度な数のストリームをグループ化することで、ストリーミングロードバッファが不足してメモリからストリーミングラインが再フェッチされるのを回避できます。
- ストリーミングラインからすべての16Byteアライメントの読み込みが発生するまで、ストリーミングラインに書き込むことは避けてください。書き込まれたストリーミングラインから16Byteのアイテムを読み取ると、ストリーミングラインが再取得される可能性があります。
- ストリーミングライン内の16Byteのアイテムを複数回読み取らないようにする。特定の16Byte項目の反復ロードにより、ストリーミング回線が再取得される可能性があります。
- ストリーミングロードバッファは、WCメモリタイプ特性を反映しているため、他のエージェントからの操作でスヌープする必要はありません。ソフトウェアは、他の論理プロセッサまたはバスエージェントに関してデータコヒーレンシを提供するために、そのような一貫性動作に頼るべきではaありません。 むしろ、ソフトウェアは、生産者と消費者との間のWCメモリアクセスの一貫性を保証しなければなりません。
- ストリーミングロードは弱く発注される可能性があり、他のメモリ操作に関してソフトウェアが順不同で実行されるように見える可能性があります。ストリーミングロードの間、またはストリーミングロードと他のメモリ操作の間で順序を保存する必要がある場合、ソフトウェアは明示的にMFENCEを使用する必要があります。
- ストリーミングロードは、副作用を持つI/Oデバイスにマップされたメモリアドレス、またはこれらのデバイスへの読み出しが破壊的であることを参照するために使用してはなりません。これはMOVNTDQAが本質的に投機的であるためです。

例12-1に、WCメモリ領域にアクセスする生産者-消費者の状況でMOVNTDQAを使用する原則を示す基本的なアセンブリシーケンスのスケッチを示します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/26eb468f-27a9-0081-ff82-1b6fb6a90d7b.png)

#### 12.10.4 Packed Blending Instructions
SSE4.1は、ブレンド処理に使用される6つの命令(BLENDPS、BLENDPD、BLENDVPS、BLENDVPD、PBLENDVB、PBLENDW)を追加します。
ブレンド処理は、ソースオペランド内のデータ要素を条件付きで同じ宛先にコピーします。SSE4.1命令は、大部分のフィールドサイズのブレンド処理を改善します。単一の新しいSSE4.1命令は、一般に、以前のアーキテクチャを使用して2から4の演算シーケンスを置き換えることができます。
可変ブレンド命令(BLENDVPS、BLENDVPD、PBLENDW)は、暗黙のXMMレジスタ(XMM0)に格納された制御bitの使用を導入します。各フィールドの最上位bit(2の補数整数または浮動小数点の符号bit)がセレクタとして使用されます。表12-3を参照してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/0f7d6b5c-bb2a-629c-0440-a69927cd648c.png)

#### 12.10.5 Packed Integer MIN/MAX Instructions
SSE4.1は、8つのパックされた整数MINおよびMAX命令(PMINUW、PMINUD、PMINSB、PMINSD; PMAXUW、PMAXUD、PMAXSB、PMAXSD)を追加します。
4つの32bit整数のパックされたMINおよびMAX命令は、符号なしおよび符号付きDwordで動作します。2つの命令は符号付きByteで動作します。2つの命令は、符号なしWordに対して動作します。表12-4を参照してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/ed75c624-4b22-c19f-8ae2-249b1b5b1ce5.png)

#### 12.10.6 Floating-Point Round Instructions with Selectable Rounding Mode
高水準の言語とライブラリでは、さまざまな数値の丸めや例外の振る舞いを持つ丸め操作が頻繁に公開されます。SSE/SSE2/SSE3命令を使用して丸めモード関連の問題を緩和することは時折順調ではありません。
SSE4.1では、スカラおよびパックされた単精度および倍精度浮動小数点オペランドをカバーする4つの丸め命令(ROUNDPS、ROUNDPD、ROUNDSS、ROUNDSD)が導入されています。丸めモードは、現在の丸めモードを変更せずに、IEEE-754モード(Nearest、-Inf、+ Inf、Truncate)の1つから即時に選択することができます。命令が強制的に現在の丸めモードを使用することができます。即値の別のbitは、不正確精度例外を抑止するために使用されます。
SSE4.1の丸め命令は、一般に、C99関数ceil()、floor()、trunc()、rint()、nearbyint()に対する単一命令ソリューションを許可します。これらの命令は、C99 round()とF90のnint()で使用されているように、ゼロからの半分の丸めモードの実装を簡素化します。

#### 12.10.7 Insertion and Extractions from XMM Registers
SSE4.1では、汎用レジスタ(GPR)とXMMレジスタ(EXTRACTPS、INSERTPS、PINSRB、PINSRD、PINSRQ、PEXTRB、PEXTRW、PEXTRD、PEXTRQ)間のデータ挿入と抽出を簡素化する7つの命令(9つのアセンブリ命令ニーモニックに対応)を追加します。メモリにアクセスする場合、アラインメントチェックが有効になっていない限り、これらの命令のアライメントは不要です。
EXTRACTPSは、XMMレジスタ内の任意のDwordオフセットから単精度浮動小数点値を抽出し、その結果をメモリまたは汎用レジスタに格納します。INSERTPSは、32bitのメモリ位置またはXMMレジスタ内の指定された要素から、1つの浮動小数点値を宛先XMMレジスタ内の選択された要素に挿入します。さらに、INSERTPSでは、マスクを使用して任意の宛先要素に+0.0fを挿入することができます。
PINSRB、PINSRD、およびPINSRQレジスタ、またはメモリからXMMレジスタへのByte、Word、Qwordの整数値を挿入します。整数Word値の挿入はすでにSSE2(PINSRW)によってサポートされていました。
PEXTRB、PEXTRW、PEXTRD、およびPEXTRQは、XMMレジスタからByte、Word、DwordおよびQwordを抽出し、その値を汎用レジスタまたはメモリに挿入します。

#### 12.10.8 Packed Integer Format Conversions
パックされた整数の演算の一般的なタイプは、パックされた整数のゼロ拡張または符号拡張による幅広いデータ型への変換です。SSE4.1は、より小さいパック整数型からより大きな整数型に変換する12の命令(PMOVSXBW、PMOVZXBW、PMOVSXBD、PMOVZXBD、PMOVSXWD、PMOVZXWD、PMOVSXBQ、PMOVZXBQ、PMOVSXWQ、PMOVZXWQ、PMOVSXDQ、PMOVZXDQ)を追加します。
ソースオペランドは、XMMレジスタまたはメモリのいずれかにあります。宛先はXMMレジスタです。表12-5を参照してください。
メモリにアクセスする場合、アライメントチェックが有効になっていない限り、命令のアライメントは不要です。この場合、すべての変換はメモリ参照の幅に合わせる必要があります。変換された要素の数(およびメモリ参照の幅)を表12-6に示します。アラインメント要件は括弧内に示されています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/90564b0f-3d52-f2c9-2094-8e341e23ba15.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/41c9012f-0c87-d0ba-a576-180bee629ef4.png)


#### 12.10.9 Improved Sums of Absolute Differences (SAD) for 4-Byte Blocks
SSE4.1は、命令ごとに8つの4Byte幅のSAD演算を実行して8つの結果を生成する命令(MPSADBW)を追加します。PSADBWと比較して、MPSADBWは小さなチャンク(8Byteのチャンクの代わりに4Byte)で動作します。これにより、VC.1やH.264などのビデオコーディング標準に適した命令になります。MPSADBWはPSADBW(命令あたり)の絶対差演算の数の4倍を実行します。これにより、高密度モーション検索のパフォーマンスを向上させることができます。
MPSADBWは、ソースオペランドからの4Byte幅のフィールドを使用します。 128bitのソースオペランド内の4Byteフィールドのオフセットは、2つの即時制御ビットによって指定されます。MPSADBWは8つの16bit SAD結果を生成します。各16bit SAD結果は、宛先の4Byteとソースオペランドの4Byteフィールドとのオーバーラップペアから形成されます。
MPSADBWは、宛先オペランド内で11個の連続するByteを使用し、そのオフセットは即値Byteの制御bitによって指定される(すなわち、オフセットはByte 0またはByte 4からのものとすることができる)。図12-4に、MPSADBWの動作を示します。MPSADBWは、ソースおよび宛先オフセット制御、SAD演算のより高いスループット、およびより小さいチャンクサイズを提供することによって、密な動き推定の符号化を単純化することができます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/b0e92dcc-6b97-c4a8-bbb4-bc6e47134af1.png)


#### 12.10.10 Horizontal Search
SSE4.1は、8つの水平にパックされた符号なしWordのうちの1つから最小の符号なしWordの値および位置を見つける検索命令(PHMINPOSUW)を追加します。結果の値と位置(ソース内のオフセット)は、宛先XMMレジスタの下位Wordにパックされます。
迅速な検索は、多くの場合、動き推定の重要な要素です。MPSADBWとPHMINPOSUWを一緒に使用してビデオエンコードを改善することができます。

#### 12.10.11 Packed Test
パックされたテスト命令PTESTは、レガシー命令TESTの128bitに似ている。PTESTでは、source引数は通常、bitマスクのように使用されます。
PTESTは、このマスクと宛先との論理ANDを実行し、結果がゼロの場合はZFフラグを設定します。宛先との反転マスクANDがすべてゼロの場合、CFフラグ(TESTの場合はゼロ)が設定されます。宛先が変更されていないため、PTESTは(パックされた浮動小数点数の分岐やゼロフィールドの分岐など)分岐演算を単純化します。

#### 12.10.12 Packed Qword Equality Comparisons
SSE4.1では、128bitのパックされたQword等価テストが追加されました。新しい命令(PCMPEQQ)はPCMPEQDと同じですが、Qwordを持っています。

#### 12.10.13 Dword Packing With Unsigned Saturation
(省略)

### 12.11 SSE4.2 INSTRUCTION SET
7つのSSE4.2命令のうち5つは、ソースまたは宛先としてXMMレジスタを使用できます。これらには、4つのテキスト/文字列処理命令と1つのパックされたQword比較SIMD命令が含まれます。これらの5つのSSE4.2命令をプログラミングすることは、SSE2/SSSE3の128bit整数SIMDをプログラミングすることに似ています。SSE4.2は64bit整数SIMD命令を提供しません。

#### 12.11.1 String and Text Processing Instructions
SSE4.2の文字列処理命令とテキスト処理命令では、4つのオペコードが割り当てられており、伝統的にはより多くのオペコードを必要とする豊富な文字列処理機能とテキスト処理機能を提供しています。これらの4つの命令は、最大128bit(16Byteまたは8Word)の文字列またはテキスト要素を処理するためにXMMレジスタを使用します。各命令は、即時Byteを使用して豊富なプログラマブル制御をサポートします。文字列処理SSE4.2命令は、索引またはマスクのいずれかを使用して文字列要素の各ペアを処理した結果を戻します。

- 符号付きまたは符号なしのByteまたはWordからなる文字列/テキストフラグメントの処理
- Word/Byte要素に対する4種類の文字列比較演算
- 明示的な長さまたは暗黙のヌル終了を使用して、長さが16Byte未満の部分文字列またはフラグメントのサポート
- すべての文字列/テキスト要素のペアについて、単一の命令で実行される最大256個の比較演算
- 比較による中間結果の組み込みの組み込み
- 中間結果に対する処理のプログラム可能な制御
- インデックスまたはマスクの観点からの出力形式のプログラム可能な制御
- インデックスフォーマットの双方向サポート
- 2つのマスクフォーマットのサポート:bitまたは自然な要素の幅
- メモリオペランドに16Byteのアライメントを必要としない

テキスト/文字列フラグメントを処理する4つのSSE4.2命令は次のとおりです。

- PCMPESTRI - バックされた明示的な長さの文字列を比較し、ECX/RCXでインデックスを返す。
- PCMPESTRM - パックされた比較明示的長さの文字列を比較し、XMM0のマスクを返す。
- PCMPISTRI - パックされた暗黙的な長さの文字列を比較し、ECX/RCXでインデックスを返す。
- PCMPISTRM - パックされた暗黙的な長さの文字列を比較し、XMM0でマスクを返す。

4つすべてで、操作を制御するために即値Byteを使用する必要があります。2つのソースオペランドは、XMMレジスタ、またはXMMレジスタとメモリアドレスの組み合わせです。即値Byteは、次の属性を持つプログラム可能な制御を提供します。

- 入力データ形式
- 比較操作モード
- 即値結果
- 出力選択

命令に関連する出力フォーマットに応じて、テキスト/文字列処理命令は、汎用レジスタ(ECX/RCX)またはXMMレジスタ(XMM0)を暗黙的に使用して最終結果を戻します。
4つのテキスト文字列処理命令のうちの2つは、文字列長を明示的に指定します。ソースオペランドに有効なデータ要素(WordまたはByteのいずれか)の数を指定するには、2つの汎用レジスタ(EDX、EAX)を使用します。他の2つの命令は、ヌル終了を使用して有効な文字列要素を指定します。データ要素は、それが最も重要でないヌルデータ要素よりも低いインデックスを有する場合にのみ、有効であると考えられます。

##### 12.11.1.1 Memory Operand Alignment
SSE4.2のテキストおよび文字列処理命令は、メモリオペランドのアライメントチェックを実行しません。
これは、XMMレジスタにアクセスする他のほとんどの128bitSIMD命令とは異なります。これらの4つの命令のアラインメントチェックがないことは、他の命令の既存の定義を変更することを意味するものではないです。

#### 12.11.2 Packed Comparison SIMD Integer Instruction
SSE4.2は、パックされた整数Qword以上の論理比較を実行する128bit整数SIMD命令PCMPGTQを提供します。

### 12.12 WRITING APPLICATIONS WITH SSE4 EXTENSIONS

#### 12.12.1 Guidelines for Using SSE4 Extensions
次のガイドラインでは、SSE4拡張機能を使用する利点を最大限に活用する方法について説明します。

- プロセッサがSSE4拡張機能をサポートしていることを確認します。
- OSがSSE/SSE2/SSE3/SSSE3拡張をサポートしていることを確認します。(SSE拡張のOSサポートは、SSE2、SSE3、SSSE3、SSE4の十分なサポートを意味します)。
- 「インテル64アーキテクチャーとIA-32アーキテクチャー最適化リファレンス・マニュアル」(Section 1.4を参照)に記載されている最適化とスケジューリングの手法を採用する。

#### 12.12.2 Checking for SSE4.1 Support
アプリケーションがSSE4.1命令を使用する前に、アプリケーションはSection 11.6.2に示す手順に従ってください。次に、以下に示す追加手順を使用してください。
プロセッサがSSE4.1(CPUID.01H：ECX.SSE4_1 [bit 19] = 1の場合)、SSE3(CPUID.01H：ECX.SSE3 [bit 0] = 1の場合)、SSSE3(CPUID.01Hの場合) ：ECX.SSSE3 [bit 9] = 1)。

#### 12.12.3 Checking for SSE4.2 Support
アプリケーションが次のSSE4.2命令(PCMPESTRI/PCMPESTRM/PCMP-ISTRI/PCMPISTRM、PCMPGTQ)を使用する前に、アプリケーションはSection 11.6.2に示す手順に従ってください。追加ステップは以下のとおりです。
プロセッサがSSE4.2(CPUID.01Hの場合：ECX.SSE4_2 [bit 20] = 1)、SSE4.1(CPUID.01Hの場合：ECX.SSE4_1 [bit 19] = 1)、SSSE3(CPUIDの場合 .01H：ECX.SSSE3 [bit 9] = 1)。
アプリケーションがCRC32命令を使用する前に、プロセッサがSSE4.2をサポートしていることを確認する必要があります(CPUID.01H：ECX.SSE4_2 [bit 20] = 1の場合)。
アプリケーションがPOPCNT命令を使用しようとする前に、プロセッサがSSE4.2(CPUID.01H：ECX.SSE4_2 [bit 20] = 1)およびPOPCNT(CPUID.01H：ECX.POPCNT [bit 23] = 1)。

### 12.13 AESNI OVERVIEW
AESNI拡張は、NIST刊行物FIPS 197で規定されているAES(Advanced Encryption Standard)を使用して128bitデータブロックの対称ブロック暗号化/復号化を加速するための6つの命令を提供する。具体的には、AES暗号化ラウンドを対象とする2つの命令(AESENC、AESENCLAST) 2つの命令(AESDEC、AESDECLAST)は等価逆暗号を使用してAES解読ラウンドを対象とします。AESIMC命令は、逆混合列変換プリミティブをターゲットとし、AESKEYGEN命令は、AES暗号化/復号化ラウンドの暗号鍵からのラウンド鍵の生成をターゲットとする。
AESは、10,12,14ラウンドの事前定義された変換でデータブロックを処理することにより、128、192、256bitの暗号鍵長を使用する暗号化/復号化をサポートします。図12-5に、128bitのプレーンテキストブロックの暗号テキストへの暗号処理を示します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/df5db23c-81dc-d467-4626-ba06cc757258.png)

あらかじめ定義されたAES変換プリミティブについては、次のセクションで説明します。また、これらの命令の命令リファレンスページの操作フローでも参照されています。

#### 12.13.1 Little-Endian Architecture and Big-Endian Specification (FIPS 197)
FIPS 197の文書はAdvanced Encryption Standard(AES)を定義し、アルゴリズムのすべてのステップをテストする一連のテストベクトルを含み、テストおよびデバッグに使用することができます。
インテル64アーキテクチャーで提供されているAES命令を使用するには、次の注意事項が重要です。FIPS 197のテキスト規則は、左に下位メモリバイト、右に上位メモリバイトを持つ16進文字列を書き込むことです。
インテルのコンベンションは逆です。 Big Endian表記とLittle Endian表記の違いと似ています。
換言すれば、FIPS文書内の128bitベクトルは、左から右へ読むと、[7:0,15:8,23:16,31:24、... 127:120]として符号化されます。Byteの内部では、エンコーディングは[7:0]であるため、左から1番目のbitが最上位ビットになります。実際には、テストベクトルは16進表記で記述されます。ここで16進数の対は異なるByteを定義します。FIPS 197表記法をインテル64アーキテクチャー互換(「リトルエンディアン」)形式に変換するには、各テストベクトルを[127:120、... 31:24、23:16、15:8、 7:0]にする必要があります。

```
Example A:
FIPS Test vector:   000102030405060708090a0b0c0d0e0fH
Intel AES Hardware: 0f0e0d0c0b0a09080706050403020100H
```

唯一の問題はテキスト形式であり、プログラマはAES命令を使用するときにコードでByte反転を実行する必要はないことを指摘しておきます。

##### 12.13.1.1 AES Data Structure in Intel 64 Architecture
このドキュメントで定義されているAES命令は、1つまたは2つの128bitソースオペランド、StateおよびRound Keyで動作します。アーキテクチャの観点からは、状態はXMMレジスタに入力され、ラウンドキーはXMMレジスタまたは128bitメモリ位置のいずれかに入力されます。
AESアルゴリズムでは、状態(128bit)は4つの32bitDword(AES用語では「ワード」)として見ることができます：X3、X2、X1、X0。
状態は、16Byteのセットとして見ることもできます。16Byteは、i、j = 0,1,2,3のS(i、j)が次のように32bitの「ワード」を構成するByteの4*4行列として見ることもできます。

X0 = S (3, 0) S (2, 0) S (1, 0) S (0, 0)
X1 = S (3, 1) S (2, 1) S (1, 1) S (0, 1)
X2 = S (3, 2) S (2, 2) S (1, 2) S (0, 2)
X3 = S (3, 3) S (2, 3) S (1, 3) S (0, 3)

次の表(表12-8-表12-11)は、128bit状態のさまざまな表現を示しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/b39c30ab-d421-907c-1fdf-0ddd214dc918.png)


```
Example:
FIPS vector: d4 bf 5d 30 e0 b4 52 ae b8 41 11 f1 1e 27 98 e5
```

このベクトルは、 "最下位"Byte d4と重要なByte e5(FIPSドキュメントのBig Endianフォーマットで書かれています)を持っています。それがIA表記法に変換されるとき、符号化は次のようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/254464/0dc4484e-76d3-665a-62b0-8ab636252a5b.png)


#### 12.13.2 AES Transformations and Functions
以下の関数と変換は、AES命令拡張AESDEC、AESDECLAST、AESENC、AESENCLAST、AESIMC、AESKEYGENASSISTのアルゴリズム記述で使用されます。
これらの変換は、ここではリトルエンディアン形式で表現されています(FIPS 197のドキュメントとは異なります)。

(以下省略)

#### 12.13.3 PCLMULQDQ
(省略)

#### 12.13.4 Checking for AESNI Support
アプリケーションがAESNI命令またはPCLMULQDQを使用する前に、アプリケーションはSection 11.6.2に示す手順に従ってください。次に、以下に示す追加手順を使用してください。
プロセッサがAESNIをサポートしていることを確認します(CPUID.01Hの場合：ECX.AESNI [bit 25] = 1)。プロセッサがPCLMULQDQをサポートしていることを確認します(CPUID.01Hの場合：ECX.PCLMULQDQ [bit 1] = 1)。