2010年03月11日

Clang と LLVM を使ってみる。

前回は Clang フロントエンドだけをビルドしました。

今回は LLVM もビルドして、実際に使ってみます。とはいっても、前回と同様に LLVM.sln を開いて、ALL_BUILD するだけです。時間がかかるかなと思って前回は試さなかったのですが、10 分もかかりませんでした。

lli.exe (LLVM 仮想マシン本体。JVM の java コマンドのようなもの)、llc.exe (ネイティブアセンブリコードへのトランスレータ) の他に、llvm-as.exe や llvm-ld.exe、llvm-nm.exe など、おなじみの binutils ライクなコマンド群が生成されます。


まず、GCC にパスが通っていれば、Clang はデフォルトで gcc をアセンブラとして使用するので、通常の実行形式が作れます。
(PATH の位置などは、環境に応じて適宜読み替えてください。)
C:\llvm\work>PATH %PATH%;C:\llvm\bin\debug;C:\MinGW\bin

C:\llvm\work>cat t.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("hello, world\n");
    return 0;
}

C:\llvm\work>clang t.c

C:\llvm\work>ls
a.out           t.c

C:\llvm\work>a.out
hello, world
clang.exe で LLVM アセンブリコードを生成し、llvm-as.exe でアセンブルし、lli.exe で実行することもできます。
C:\llvm\work>clang -emit-llvm -S t.c

C:\llvm\work>ls
t.c             t.s

C:\llvm\work>llvm-as t.s

C:\llvm\work>ls
t.c             t.s             t.s.bc

C:\llvm\work>lli t.s.bc
hello, world
どうも設定が悪いのか、直接ビットコードを生成することはできない感じです。そのため、-S を経由しているのですが、拡張子が重複してしまい t.s.bc とか変なことになってます。
C:\llvm\work>clang -emit-llvm t.c
clang: error: 'i686-pc-win32': unable to pass LLVM bit-code files to linker
bc ファイルは、BitCode のことで、Java のクラスファイル(というと語弊がありますが。LLVM には、JVM のよりも Low-Level な、機械語に近い構造しか存在しませんので。)のようなものです。 bc ファイルを逆アセンブルすると ll ファイルが生成されますが、これは clang -S で生成されるものと全く同じ内容です。(ファイル名などは当然異なりますが。)
C:\llvm\work>llvm-dis t.s.bc

C:\llvm\work>ls
t.c             t.s             t.s.bc          t.s.ll

C:\llvm\work>diff t.s t.s.ll
1c1
< ; ModuleID = 't.c'
---
> ; ModuleID = 't.s.bc'
この ll ファイルなり、s ファイルなりは、LLVM のアセンブリコードなわけですが、これをネイティブ環境のアセンブリコードに変換するには、llc.exe コマンドを使用します。
C:\llvm\work>llc t.s.ll

C:\llvm\work>ls
t.c             t.s             t.s.bc          t.s.ll          t.s.s

C:\llvm\work>cat t.s.s
        .def     _main; .scl    2;      .type   32;     .endef
        .text
        .globl  _main
        .align  16, 0x90
_main:                                  # @main
# BB#0:                                 # %entry
        subl    $20, %esp
        movl    $0, 16(%esp)
        movl    24(%esp), %eax
        movl    %eax, 12(%esp)
        movl    28(%esp), %eax
        movl    %eax, 8(%esp)
        movl    $L_.str, (%esp)
        call    _printf
        movl    $0, 16(%esp)
        xorl    %eax, %eax
        addl    $20, %esp
        ret

        .data
L_.str:                                 # @.str
        .asciz   "hello, world\n"
これは当然、gcc でアセンブル・リンクして実行できます。
C:\llvm\work>gcc t.s.s

C:\llvm\work>ls
a.exe           t.c             t.s             t.s.bc          t.s.ll
t.s.s

C:\llvm\work>a.exe
hello, world
いろいろややこしい構造になっていますが、これは LLVM が、仮想マシンの上でプロファイルを取得しながらの、動的な最適化を行うためのプラットフォームだからです。

ネイティブコード生成は、その時点で情報が欠落し、それ以上の最適化を阻害するため、LLVM の本来の目標 Multi-Stage optimization からすると邪道で、とりあえず GCC の置き換え、C/C++/Obj-C コンパイラとして使用するための、ある意味ではオマケのようなものだと言えます。(ただし、そのおかげでいち早く FreeBSD などで実用性が認められたわけですが。)

トラックバックURL

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード