NASMでx86のSIMDを使う

2002.07.23

IA-32(x86)にはSIMD(Single Instruction Multi Data)と呼ばれる拡張命令があります。これは1回の命令で複数のデータを同時(並列)に処理できるので、マルチメディア関係のソフトの処理速度を上げるのに有効です。

SIMD拡張命令はMMXから始まり、3DNow!、SSE、SSE2などの種類があります。これらの命令をLinuxの環境で使うにはいくつかの方法がありますが、ここではNASM(The Netwide Assembler)を使った方法を説明します。



使用した環境
AthlonXP 1900+ (LoquatXP)
LedHat Linux 7.2(Linux 2.4.7)
NASMのインストール
SourceForge.netProject:The Netwide Assemblerからソースなりバイナリなりをダウンロードしてインストールする。特に問題ないと思うので詳細は割愛。
アセンブラのテストコード(test_copy.asm)
bits 32
    section .data
    align   16

D_CONST
    dd  123, 456

    section .text

;
; void test_copy(int *dst, int *src)
;

    global  test_copy
    align   16

test_copy
    push    ebp
    mov     ebp, esp
    mov     ecx, [ebp + 8]      ; dst
    mov     eax, [ebp + 12]     ; src
    movq    mm0, [D_CONST]      ; mm0 = 456:123

    movq    mm7, [eax]          ; mm7 = src[1]:src[0]
    movq    [ecx], mm7
    movq    [ecx + 8], mm0

    femms
    pop     ebp

    ret

mm0やmm7がMMXレジスタです。SSE/SSE2用のレジスタはxmm?(?は0〜7の数字)で使えます。femmsは3DNow!なのでAMDのCPU専用です。IntelのCPUの場合はemmsを使います。movqは8byteの転送命令なので、上記のプログラムはsrcのアドレスから8バイト分をdstのアドレスにコピーし、その後に固定データを書き込みます(このプログラムは単に動作テストのためで動作には何の意味もありません)。データ領域のサイズ指定は4バイト単位の場合はdd、2バイト単位の場合はdw、1バイト単位の場合はdbと指定します。

アセンブラのコンパイル
% nasm -f elf test_copy.asm

ファイル出力のオプションとしてelfを指定します。上記の実行で正しくコンパイルされれば、test_copy.oが作成されます。

C/C++から使う(test.cc)
#include <stdio.h>

extern "C" {
extern void test_copy(int *dst, int *src);
}

int main(int argc, char *argv[])
{
    int a1[2], a2[4];
	
    a1[0] = 10;
    a1[1] = 12;

    test_copy(&a2[0], &a1[0]);
    printf("a2[0] = %d a2[1] = %d \n", a2[0], a2[1]);
    printf("a2[2] = %d a2[3] = %d \n", a2[2], a2[3]);

    return 0;
}

gccを使う場合はextern "C"でくくる必要はありません。g++を使う場合はこれがないとリンクエラーになります。

コンパイルとリンク
% g++ -o test test.cc test_copy.o


番外編:Windowsでコンパイル

NASMのソースコードはWindows上のコマンドラインでもそのままコンパイルできます。Windows用のNASM(nasmw.exe)が必要なのでダウンロードしてきます。パスの通ったディレクトリにnasmw.exeをコピーすればOK。

% nasmw -f win32 test_copy.asm

これで、Visual C++でリンクできるオブジェクトファイル(test_copy.obj)ができます。

Borland C++の場合はオプションを-f objに変更すれば良いようです(試したことなし)。



参考資料
1. AMD-K6 MMX Enhanced Processor Multimedia Technology (20726)
2. 3DNow! Technology Manual (21928)
3. AMD Extensions to the 3DNow! and MMX Instruction Sets Manual (22466)
4. AMD Athlon Processor x86 Code Optimization Guide (22007)

以上はAMDのホームページ(この辺)から入手できます。1〜3の資料で拡張分も含めたMMXと3DNow!の命令がわかります。

5. IA-32インテルアーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル(上、中、下)

以上はIntelのホームページ(この辺)から入手できます。命令のマニュアルは中巻です。残念ながらAMDのマニュアルのようにSIMD拡張命令だけを抜き出したものは見つからなかったので、私は中巻の巻末にあるSIMD命令の一覧を使って、SIMD命令のページだけを印刷してSSE、SSE2用のマニュアルを作って使っています。

6. ch3, プログラムの高速化・最適化, No.10, Cマガジン, 2001
7. J.Bush, T.S.Newman, 3DNow!を使い倒せ, No.3, Linux Japan, 2000

以上はSIMD拡張命令を使ってみようかと思うきっかけとなった雑誌の記事です。

8.光成, Advanced Optimization, 光成さんのページ

上記のページはSIMD命令を全体的に見渡すのにとても役にたちました。




Linuxのページに戻る