LLVM は Low Level Virtual Machine の略で、プログラミング言語に対する仮想マシン(コンパイラ・インフラストラクチャ)です。この仮想マシンには RISC CPU のようなインストラクションセット(マシン語)が構成されています。プログラミング言語で記述されたプログラムを、LLVM のフロントエンドのコンパイラが仮想マシン LLVM のマシン語に翻訳し、LLVM が言語やプラットフォームから独立して最適化を行い、ターゲット CPU のマシン語を生成します。
clang(クラング)は、C 系のプログラミング言語 (C, C++, Objective C/C++) をサポートする LLVM のフロントエンド(コンパイラ)で、GCC と互換性があります。また、プログラムを開発する IDE とインターフェースを取りやすいように考慮された設計になっています。
SYNOPSIS
clang [-c|-S|-E] -std=standard -g
[-O0|-O1|-O2|-Os|-O3|-O4]
-Wwarnings... -pedantic
-Idir... -Ldir...
-Dmacro[=defn]
-ffeature-option...
-mmachine-option...
-o output-file
input-filenames
どちらのライセンスも、BSD ライセンスをベースにした University of Illinois/NCSA Open Source License です。
さて、Fedora 12 で LLVM と clang 関連 RPM を利用するには、yum で次のようにしてインストールします。
$ yum install llvm* clang*
LLVM、clang のバージョンは 2.6 で、最新の安定版です。
clang で生成したバイナリが、どの程度のパフォーマンスを持っているのか気になるので、Tcl の nightly-CVS(Tcl8.6b1.1, tcl-20100415.tar.gz) ファイルをダウンロードして、gcc と clang それぞれでコンパイルしたバイナリのベンチマークを取ってみました。
Tcl のビルドに使用したスクリプトを以下に示します。
#!/bin/sh
# C compiler
#export CC=gcc
export CC=clang
# constants
export cvs_ver="20100415"
# remove old sources
echo "### Removing old sources & binaries"
rm -fR tcl
# extract sources
echo "### Expanding sources to build"
tar zxvf tcl-${cvs_ver}.tar.gz
# build Tcl
echo "### build Tcl"
cd tcl/unix
./configure --prefix=$HOME
make
make test
make install
clang でビルドした際に、警告メッセージが gcc の時と違って、ずいぶんと親切な内容であったことが印象的でした。例を以下に示します。
clang -c -DNDEBUG -O2 -pipe -fvisibility=hidden -Wall -fPIC -DBUILD_tcl -I"."
-I/home/bitwalk/src/tcl/unix -I/home/bitwalk/src/tcl/generic -I/home/bitwalk/src
/tcl/libtommath -DPACKAGE_NAME=\"tcl\" -DPACKAGE_TARNAME=\"tcl\" -DPACKAGE_VERSI
ON=\"8.6\" -DPACKAGE_STRING=\"tcl\ 8.6\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS
=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1
-DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAV
E_UNISTD_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REEN
TRANT=1 -D_THREAD_SAFE=1 -DTCL_THREADS=1 -DTCL_CFGVAL_ENCODING=\"iso8859-1\" -DH
AVE_ZLIB=1 -DTCL_SHLIB_EXT=\".so\" -DTCL_CFG_OPTIMIZED=1 -DTCL_CFG_DEBUG=1 -DTCL
_TOMMATH=1 -DMP_PREC=4 -D_LARGEFILE64_SOURCE=1 -DTCL_WIDE_INT_TYPE=long\ long -D
HAVE_STRUCT_STAT64=1 -DHAVE_OPEN64=1 -DHAVE_LSEEK64=1 -DHAVE_TYPE_OFF64_T=1 -DHA
VE_GETCWD=1 -DHAVE_MKSTEMP=1 -DHAVE_OPENDIR=1 -DHAVE_STRTOL=1 -DHAVE_WAITPID=1 -
DHAVE_GETADDRINFO=1 -DHAVE_GETPWUID_R_5=1 -DHAVE_GETPWUID_R=1 -DHAVE_GETPWNAM_R_
5=1 -DHAVE_GETPWNAM_R=1 -DHAVE_GETGRGID_R_5=1 -DHAVE_GETGRGID_R=1 -DHAVE_GETGRNA
M_R_5=1 -DHAVE_GETGRNAM_R=1 -DHAVE_GETHOSTBYNAME_R_6=1 -DHAVE_GETHOSTBYNAME_R=1
-DHAVE_GETHOSTBYADDR_R_8=1 -DHAVE_GETHOSTBYADDR_R=1 -DUSE_TERMIOS=1 -DHAVE_SYS_T
IME_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_GMTIME_R=1 -DHAVE_LOCALTIME_R=1 -DHAVE_MKT
IME=1 -DHAVE_TM_GMTOFF=1 -DHAVE_TIMEZONE_VAR=1 -DHAVE_STRUCT_STAT_ST_BLOCKS=1 -D
HAVE_STRUCT_STAT_ST_BLKSIZE=1 -DHAVE_BLKCNT_T=1 -DHAVE_INTPTR_T=1 -DHAVE_UINTPTR
_T=1 -DHAVE_SIGNED_CHAR=1 -DHAVE_LANGINFO=1 -DHAVE_MKSTEMPS=1 -DHAVE_FTS=1 -DHAV
E_SYS_IOCTL_H=1 -DTCL_UNLOAD_DLLS=1 /home/bitwalk/src/tcl/generic/tclBasic
.c
/home/bitwalk/src/tcl/generic/tclBasic.c:7652:2: warning: expression result unus
ed [-Wunused-value]
TclGetLongFromObj(NULL, objPtr, &iResult);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/bitwalk/src/tcl/generic/tclInt.h:2460:57: note: instantiated from:
? ((*(longPtr) = (objPtr)->internalRep.longValue), TCL_OK) \
^
/home/bitwalk/src/tcl/generic/tcl.h:635:18: note: instantiated from:
#define TCL_OK 0
^
/home/bitwalk/src/tcl/generic/tclBasic.c:7892:2: warning: expression result unus
ed [-Wunused-value]
TclGetLongFromObj(NULL, objPtr, &i);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/bitwalk/src/tcl/generic/tclInt.h:2460:57: note: instantiated from:
? ((*(longPtr) = (objPtr)->internalRep.longValue), TCL_OK) \
^
/home/bitwalk/src/tcl/generic/tcl.h:635:18: note: instantiated from:
#define TCL_OK 0
^
/home/bitwalk/src/tcl/generic/tclBasic.c:8897:5: warning: expression result unus
ed [-Wunused-value]
TclGetString(cmdObjPtr);
^~~~~~~~~~~~~~~~~~~~~~~
/home/bitwalk/src/tcl/generic/tclInt.h:3957:33: note: instantiated from:
((objPtr)->bytes? (objPtr)->bytes : Tcl_GetString((objPtr)))
~~~~~~~~ ^~~~~
3 diagnostics generated.
Tcl のベンチマークは、Tcl benchmark tests のサイトのスクリプトの一部を使用しました。32bit の x86 版 Fedora 12 上で、gcc と clang それぞれのベンチマークを取った結果は以下のようになりました。数値の単位は「秒」です。
### gcc
$ ls -l libtcl8.6.so
-r-xr-xr-x. 1 bitwalk bitwalk 1393392 2010-04-17 09:15 libtcl8.6.so
$ tclsh8.6 benchmark.tcl
1000000 repeats in 0.169659
10000 iterative factorial(100) in 73.867148
10000 iterative factorial(100) with 'if' in 73.777363
10000 recursive factorial(100) in 88.282079
1000 exec calls in 1.600121
total time was 237.69637
### LLVN & clang
$ ls -l libtcl8.6.so
-r-xr-xr-x. 1 bitwalk bitwalk 1371875 2010-04-17 09:54 libtcl8.6.so
$ tclsh8.6 benchmark.tcl
1000000 repeats in 0.165494
10000 iterative factorial(100) in 79.013924
10000 iterative factorial(100) with 'if' in 79.165719
10000 recursive factorial(100) in 95.940107
1000 exec calls in 1.549376
total time was 255.83461999999997
64bit 版 Fedora 12 上でも、--enable-64bit スイッチを加えてビルドした Tcl を試しましたが、現時点では、どちらの場合も、clang でビルドしたバイナリによる計算速度は、gcc でビルドしたものより 5 - 10 % 程度遅いという結果になりました。バイナリのサイズは clang で生成した方が、やや小さくなっています。
IDE でプログラムを開発する場合のメリットを調べる必要があります。機会があれば紹介しようと思います。
参考サイト
[1] The LLVM Compiler Infrastructure Project
[2] LLVM 2.6リリース - SourceForge.JP Magazine : オープンソースの話題満載
[3] LLVMのコンパイラ「Clang」、セルフホスティングに成功 - SourceForge.JP Magazine : オープンソースの話題満載
0 件のコメント:
コメントを投稿