SSE2 には MASKMOVDQU という命令があって、16バイトの長さを持つ SSE レジスタの一部分だけを書き込むことができます。
さて、「IA-32 インテル アーキテクチャ ソフトウェア・デベロッパーズ・マニュアル」にある MASKMOVDQU の説明文には以下のようなことが書いてあります。
ただし、MASKMOVDQU 命令で所有権の読み込みを行ってはならない。これを行うと、ストアの前に元のデータを割り当てることなく、バイトマスクを使用してデータが直接書き込まれるため、不要な帯域幅が発生する。
意味が分かりません。というか言っていることがおかしくないですか。
仕方ないので英語版である「Intel 64 and IA-32 Architectures Software Developer’s Manuals」の同じ箇所を見ると、以下のようになっています。
MASKMOVDQU should not cause a read for ownership; doing so generates unnecessary bandwidth since data is to be written directly using the byte-mask without allocating old data prior to the store.
should not…? この場合の should not は技術文書でよく使われる SHOULD NOT (すべきでない)ではなくて、期待や可能性を表す should の否定形、つまり「そうはならない(だろう)」なんじゃないですかね。そうしたら意味が通るし。
というわけで、より適切な訳は以下のような感じでしょうか。カッコ内は訳者による補足。
MASKMOVDQU 命令は(キャッシュラインの)所有権を得るための読み込みを行わない。ストアの前に(キャッシュラインに)元のデータを割り当てることなく、データはバイトマスクを使用して直接書き込まれるため、そうする(=所有権を得るための読み込みを行う)と不要な帯域幅が発生してしまう。
「read for ownership」が「所有権の読み込み」と訳されているあたり、自動翻訳だったんですかね。
ちなみに、なんでこんなこと調べているかというと、Ut Video Codec Suite の ULY2 から RGB24 に色空間変換をする際に、MASKMOVDQU を使って効率的に RGB24 のバッファに書き込みができるかと思っていたからです。RGB24 だと 1ピクセル当たり3バイトなので非常に扱いづらいわけですが、MASKMOVDQU 命令を使えばバイト単位に分けずともマスクを使うことで一発で書き込めます。
なのですが、書き込もうが書き込むまいが 16バイト分の全体が書き込み可能かチェックされる(つまり、たとえマスクが全部 0 で一切書き込まない指定であっても、書き込み不可能なページに対して MASKMOVDQU 命令を発行すると一般保護例外が発生する)という挙動になっています。そうすると、RGB24 のバッファの末端ではページ境界をはみ出してコケる可能性があり、結局あきらめました。
一方で Sandy Bridge で実装される AVX で追加された VMASKMOV 命令だと、マスクによって読み書きしない指定になったバイトに関してはチェックされないと明記されているため、安心して使うことができます。でも Sandy Bridge はしばらく先なんですよねぇ…
VMASKMOV 命令を使おうとしたのだけど
よくよく命令セットリファレンスを読んでみたら、実際には VMASKMOVPS/VMASKMOVPD 命令で、パックド浮動小数点数用でした。リファレンスをさらっと読む限り Ivy Bridge でも実装されなさそうな…