2008-10-27

透過的なLLVM (10)

前回のハックは美しくなかった。Lame 3.98.2ではハックが働いたけれど、x264ではうまく働かなかった。問題は、畢竟、アーカイブファイルにオブジェクトファイルの完全パスが含まれていることにほかならないのだけれど、手を抜いたのは私の責任だ。カレントディレクトリへのシンボリックリンクと言わず、ディレクトリを作成するほうが美しく、汎用性があった。

#! /bin/sh

set -e

case "$1" in
    *x*)
        for i in `llvm-ar tv "$2" | awk '{ printf " %s", $9 }'`; do
            d=`dirname "$i"`
            mkdir -p "$d"
        done
        ;;
esac
llvm-ar "$@"

当初はカレントディレクトリにオブジェクトファイルを集めることに固執していたんだけど、どうやら、その必要性はないらしい。

2008-10-24

透過的なLLVM (9)

SUSv3はarのx命令を規定しており、llvm-arもx命令を提供する。アーカイブファイルからオブジェクトファイルを抽出するという機能は共通だが、共通の動作は期待できないかもしれない。llvm-arはfモディファイヤを与えない限り、オブジェクトファイルの完全パスをアーカイブファイルに保存する。x命令は、保存された完全パスにオブジェクトファイルを書き出そうとする。ディレクトリが存在していない場合、抽出は失敗する。

Lame 3.98.2はビルドにx命令を使用する。libmpgdecoder.aとliblamevectorroutines.aからオブジェクトファイルを抽出して、libmp3lame/.libs/libmp3lame.0.0.0.{a,dylib}にまとめる(実際の仕事はlibtoolシェルスクリプトが行う)。

$ llvm-ar tv mpglib/.libs/libmpgdecoder.a
brw-r--r--  501/  20     6508 Oct 23 09:23:37 2008 .libs/common.o
brw-r--r--  501/  20     8116 Oct 23 09:23:38 2008 .libs/dct64_i386.o
brw-r--r--  501/  20    15224 Oct 23 09:23:39 2008 .libs/decode_i386.o
brw-r--r--  501/  20    18900 Oct 23 09:23:40 2008 .libs/interface.o
brw-r--r--  501/  20     6344 Oct 23 09:23:40 2008 .libs/layer1.o
brw-r--r--  501/  20    12296 Oct 23 09:23:41 2008 .libs/layer2.o
brw-r--r--  501/  20    74804 Oct 23 09:23:43 2008 .libs/layer3.o
brw-r--r--  501/  20     5284 Oct 23 09:23:44 2008 .libs/tabinit.o
$ llvm-ar tv libmp3lame/vector/.libs/liblamevectorroutines.a
brw-r--r--  501/  20     1932 Oct 23 09:23:46 2008 .libs/xmm_quantize_sub.o

xmm_quantize_sub.oは18文字あるので、アーカイブファイルの作成時にfモディファイヤをつけて対処することはできない。簡単な解決策は美しくないハックだ。x命令の実行前にカレントディレクトリへのシンボリックリンクを作成する。

#! /bin/sh

set -e

case "$1" in
    *x*)
        for i in `llvm-ar tv "$2" | awk '{ printf " %s", $9 }'`; do
            ifs="$IFS"
            IFS="/"
            for d in `dirname "$i"`; do
                if [ -f "$d" ] || [ -d "$d" ] || [ -h "$d" ]; then
                    :
                else
                    ln "-s" "." "$d"
                fi
            done
            IFS="$ifs"
        done
        ;;
esac
llvm-ar "$@"

第一引数が命令とモディファイヤで、第二引数がアーカイブファイルであるならば、シェルスクリプトはほとんどの場合うまく働き、期待した動作を行う。嫌がらせみたいなオブジェクトファイルのパスを含む場合は、もちろん無理だけど。

2008-10-16

変奏と反復 (3a)

変奏なのだ、これは。

彼はといえば、重荷を背負い、をのぼったりくだったりしていた。坂が多い街なのだ、横浜は。名高い女子校は丘のうえにあった。坂と運河元町寿町を分けた。丘のうえには名高い教会があり、そのすじでは名高いプールつきの邸宅があり、丘のむこうの基地はすでになかった。仕立ての良い制服と透徹を身にまとい、彼は歩きつづけた。そのころの彼は、なにしろ、モールトンを手に入れてなかった。

いまもって。いまなお。

長い髪を切った少女が「ぼくたちの失敗」を唄うのを眺める彼は、唇をしめらすアルコールと同じくらい引きのばされたあらゆる二度めのものどものことを思った。育ちのよい少女がカラオケボックスを去り、身持ちのよろしい少女が石川町の改札に消えてもなお、彼はそのことを思いつづけた。

「ぼくは上京するぜ」と、彼は言った。少女は首をかしげると、切りそろえられた前髪が微笑した。「莫迦じゃない」と、少女は身をひるがえした。彼が神田川沿いの風呂なしのアパートに住むのは、それからもうすこし先の話だ。

2008-10-14

変奏と反復 (2)

ヴァリエーション、いくたびの。図書館の庭、通りからは目立たない広場。カップ酒をあおり、おじさんは故郷の話を繰り返した。「兄ちゃんがよう、偉くなってよう、おれらみたいなのをよう」イテレーション、いくたびも。なしくずしの二十一世紀、マンガ喫茶と個室ビデオ屋は相似形の双生児、忘れないことだけを綱領に、時間と空間が混ぜこぜになった都市を、速度だけを武器として。

透過的なLLVM (8)

前回は完膚なきまでに事実を誤認していた。llvm-arはbitcodeとnative codeを同時に含む。llvm-arのマニュアルに曰く、

t[v]
Print the table of contents. Without any modifiers, this operation just prints the names of the members to the standard output. With the v modifier, llvm-ar also prints out the file type (B=bitcode, Z=compressed, S=symbol table, blank=regular file), the permission mode, the owner and group, the size, and the date. If any files are specified, the listing is only for those files. If no files are specified, the table of contents for the whole archive is printed.

t命令にvモディファイヤを付けると、たとえばこんな出力が得られる。

 rw-r--r--  501/  20      636 Oct 14 10:46:35 2008 bar0.o
 rw-r--r--  501/  20      544 Oct 14 10:46:35 2008 bar1.o
brw-r--r--  501/  20      544 Oct 14 10:46:35 2008 foo0.o
brw-r--r--  501/  20      540 Oct 14 10:46:35 2008 foo1.o

foo0.oとfoo1.oがbitcodeのオブジェクトファイルで、bar0.oとbar1.oがnative codeのオブジェクトファイルだ。x命令を使うと、アーカイブファイルからオブジェクトファイルを抽出できる。

x[oP]
Extract archive members back to files. The o modifier applies to this operation. This operation retrieves the indicated files from the archive and writes them back to the operating system's file system. If no files are specified, the entire archive is extract.

だけど、llvm-ldは、bitcodeとnative codeの両方を含むアーカイブファイルを良きにはからってくれない(tools/llvm-ld/llvm-ld.cppを読むとItemsNativeLinkItemsに二分しちゃってる)。だったら、x命令を使用してオブジェクトファイルを抽出して、bitcodeだけからなるアーカイブファイルとnative codeだけからなるアーカイブファイルを作成しよう。下記はコンセプトを実証するためのもので、オブジェクトファイルがディレクトリ階層を持っている場合に破綻する(かもしれない)。

#! /bin/sh

set -e

file="$1"
shift

b_objs=`llvm-ar tv "$file" | awk '/^b/ { printf " %s", $9}'`
n_objs=`llvm-ar tv "$file" | awk '/^ / { printf " %s", $9}'`

d=`dirname "$file"`
s=`printf '%s' "$file" | sed -e 's/.*\(\..*\)$/\1/'`
n=`basename "$file" "$s"`

cd "$d"
mkdir "-p" "$n-o"
cd "$n-o"
llvm-ar "xo" "../$n$s"
llvm-ar "rc" "$n-b$s" $b_objs
ar "rc" "$n-n$s" $n_objs
mv "$n-b$s" "$n-n$s" ".."
cd ..
rm "-fr" "$n-o"

話はほとんど、これでおしまい。ただし、native codeがbitcodeのシンボルを参照する場合(多くの場合参照する、そもそも、参照しなかったらそのコードに意味がない)、できあがったアーカイブファイルをリンクする際に-disble-internalizeの付与を検討するべきだ。すべてのbitcodeが先にリンクされ(願わくば最適化され)、その後native codeがリンクされる。最適化はnative codeが参照しているシンボルをどっかにやっちゃうかもしれない(native codeからしか参照されていなかったら、たぶんどっかにやっちゃう)。

2008-10-10

変奏と反復 (1c)

ビデオライブラリーのブースで『カサブランカ』が再生しながら、彼はロディアのレポートパッドに論文を書きあぐねている。主題はあった。かかる主題のために『摩利と新吾』を読んだのだ。けっして髪を切った少女のためではなく。隣のブースで港湾労働者のおじさんがクロサワを見ている。自治体が運営する図書館は、当該自治体に居住するか、当該自治体に学校や職場がある者にサービスを提供する。上階の自習室は受験勉強に勤しむ若者たちに占拠された。本棚と本棚の間の机は良き市民たちが頑としてゆずらない。だけど、おじさんたちが鍵括弧なしの横浜で働いていることは間違いない。闘争は図書館内に酒を持ちこまないことで決着し、地階のビデオライブラリーが勝ちとられた。

「兄ちゃん、」と、おじさんは言った。飛行機が飛びたつのをおじさんは辛抱強く待っていた。クロード・レインズがヴィシー水をゴミ箱に放る。「酒をさ」
「そんなにお金ないから、みんなのぶんはないよ」
「ああ、うん、うん、いや、いいんだ」
彼はポケットに移しておいた千円札をおじさんに渡す。そのころの彼に、千円は大金だった。だけど財布にマンガを買うためのお金は残っていたし、少女と元町のマクドナルドでハンバーガーを食べるためのお金は鞄の底に隠してあった。
「いや、どうも、ありがとう」
その顔に浮かんだ表情から眼をそらさないように、彼は歯をくいしばる。おじさんはデッキからビデオを取り出し、返却カウンターに向かう。鉛筆を取りあげ、レポートパッドに「ゆるやかな」と書く。二重線でそれを消し、「無限にひきのばされた」と書く。

2008-10-08

変奏と反復 (1b)

柳瀬尚紀版の『フィネガンズ・ウェイク』を箱に入れ、いちばん上の棚に戻す。店頭のワゴンからムックを一冊択んでカウンターに持っていく。
「立ち読みするなら、図書館で借りりゃいいでないの」
と、左翼運動家くずれの店主がためいきをつく。
「たとえ飾られてあることがその本の目的だったとしても、」
ほとんどささやきに近い彼の言葉に、店主は眉を持ちあげる。
「最後の人民戦線たるぼくはそんなプチブル迎合主義を許さない」
「プチブルはおまえだよ」
「たこにも。だから、こうして、売り上げに貢献しようとしている」
「煙草銭にもなりゃしねえ」
一九八九年以前、一九八九年以前の状況を大正時代末期になぞらえたアンソロジーが幾冊も出版された。右も左も上も下も、長すぎた昭和に決着をつけあぐね、状況は整理されすぎていった。Xデイを待ち続け、Xデイを待ち望み、Xデイを待つことに飽き、ようやく訪れたXデイは、もちろん左翼運動家たちが望んだようなXデイではなかったのだけれど、Xに代入するべきなにものかこそが失われたものだったと気づいたときには九〇年代が始まっていた。
「小さいとはいえ立派な資本家がそんなこと言っちゃだめじゃない。金に色はないって言うよ」
「うるせえ。そんな本ばっかり読んでたら莫迦になるぞ。セットで『球根栽培法』はいかがですか」
「二重に権力の謀略じゃない、それって」
「小さいとはいえ立派な資本家だからな。バブルのころだって土地売らずにがんばったんだぜ」
「裏本売って?」
肩をすくめて、わざとらしく壁の時計に視線をやり、
「良い子のおぼっちゃんは図書館行って勉強でもする時間だ」
彼が取り出した百円玉がカウンターにぶつかってくぐもった音を鳴らした。ボストンバッグに本をしまい、彼は古本屋を出た。ウインズから桜木町に向かう人の流れにさからい、仏壇屋の並ぶ坂をのぼっていった。

2008-10-06

変奏と反復 (1a)

変奏なのだ、これは。

彼はといえば、重荷を背負い、坂をのぼったりくだったりしていた。坂が多い街なのだ、横浜は。名高い女子校は丘のうえにあった。坂と運河が元町と寿町を分けた。丘のうえには名高い教会があり、そのすじでは名高いプールつきの邸宅があり、丘のむこうの基地はすでになかった。仕立ての良い制服と透徹を身にまとい、彼は歩きつづけた。そのころの彼は、なにしろ、モールトンを手に入れてなかった。

いまもって。いまなお。

長い髪を切った少女が「ぼくたちの失敗」を唄うのを眺める彼は、唇をしめらすアルコールと同じくらい引きのばされたあらゆる二度めのものどものことを思った。育ちのよい少女がカラオケボックスを去り、身持ちのよろしい少女が石川町の改札に消えてもなお、彼はそのことを思いつづけた。

「ぼくは上京するぜ」と、彼は言った。少女は首をかしげると、切りそろえられた前髪が微笑した。「莫迦じゃない」と、少女は身をひるがえした。彼が神田川沿いの風呂なしのアパートに住むのは、それからもうすこし先の話だ。

2008-10-03

透過的なLLVM (7)

ほとんどもう、透過的にLLVMを使うことができるようになった。

Mac OS X 10.5 (darwin9) では、メディアを扱うライブラリやツール、つまり圧縮や暗号化は確かに高速になる。32bitで試した範囲ではGNU/Linuxシステム、畢竟ELF形式もビルドに問題はなさそうだ。ビルドに問題はないが、速度が向上するとは限らない。メディアを扱うライブラリやツールは、しばしばアセンブリ言語で高速なコードを記述する。Native codeがまざるとLLVMの魔法が効きにくくなる。

OpenSSLが良い例だ。OpenSSL 0.9.8iのcpuid命令の実装は、アーキテクチャごとに4個のファイルを用意している。

  • crypto/ia64cpuid.S
  • crypto/sparccpuid.S
  • crypto/x86_64cpuid.pl
  • crypto/x86cpuid.pl

さまざまのアセンブラに対応するべく、x86-64とx86はアセンブリコードを生成するPerlスクリプトとして記述されている。対応するアセンブラにELF形式は含まれるが、Mach-O形式は含まれない。つまり、Darwinで普通にビルドしたOpenSSLはもろもろのハッシュ、AESやらDESやらをCで書かれたコードで計算している。LLVMの魔法は最大の効果を発揮するだろう。

GNU/Linuxシステムで透過的にLLVMを使用するためには、no-asm付きで./configを実行する羽目になる。静的リンクライブラリはbitcodeとnative codeを同時に含むことができない。静的リンクライブラリはbitcodeとnative codeを同時に含むことはできる(というか含んでしまう)けれど、単純には正しくリンクしてくれない。アセンブリ言語でかりかりに高速化された暗号化にたちうちすることは、さしものLLVMにも難しいようだ。openssl speedで調べた限りでは。

いくつかの解決策があるだろう。

  • native codeからbitcodeへの変換
    参考: x86toLLVM?
  • インラインアセンブラへの変換
    参考: Module-Level Inline Assembly, Inline Assembler Expressions
  • LLVMの静的リンクライブラリの形式を変更する
  • bitcodeとnative codeで別々に静的リンクライブラリを分割生成
  • 正しくリンクしてくれるようにハックする。

前者ほど最適化の可能性が高く、透過的であり、しかし、実装が困難である。