コンパイラ・ドライバはコンパイラの部品をつなぎ合わせてコンパイラを構成する ためにものである。COINSには標準のコンパイラ・ドライバとして
coins.driver.Driver
というクラスが用意されている。このDriverはCコンパイラを構成するものであるが、 COINSの標準ドライバという意味でCOINS コンパイラ・ドライバとも呼ばれる。
新しい言語のコンパイラ・ドライバを得るためには、この Driverのサブクラスを作って、フロントエンドの呼び出し部分だけをオーバライドして その言語のフロントエンドを呼び出すようにすればよい。実際に、COINSのFortranコンパイラ、 PL0コンパイラ、 Simpleコンパイラなどはそのようにして作られている。
したがって、これらのコンパイラでは標準のDriverで使える各種のオプション機能が ほとんどそのまま使える。
以下では、COINS コンパイラ・インフラストラクチャに興味があるが、ま だ使用したことはないという方に向けて、 COINS のドライバ部分の設計方針、 構成、使い方などを解説している。
COINS コンパイラ・インフラストラクチャは、主に、新しいコンパイラを作 りたい人が簡単にそれをできるように支援するためのフレームワークであるの で、ドライバ部分もそれを支援することを主目的としている。このため、ドラ イバ部分は、コンパイラ・ドライバを作成するための Java 言語 API と、そ れを利用して作られたコンパイラ・ドライバから成っている。
現在 のリリースには、コマンド・ライン・インタフェース(CLI)を利用した、オー ソドックスなスタイルのコンパイラ・ドライバ(CLI ドライバ)が含まれてい る。それを以下では、たんにコンパイラ・ドライバと呼んでいる。
後者のユーザを、以下では「オペレータ」と呼ぶ。また、断りなく「ユーザ」 と書かれている場合、それはオペレータ以外のユーザを指す。
オペレータはコンパイラを使うために複雑な手順を踏むことはしたくなかろ う。可能ならば Makefile の CC 変数を変更するだけで済ませたいに違いない。 このため、 COINS は、上記のドライバ API を使用して、コマンド・ライン・ インタフェース(CLI)を利用したオーソドックスなスタイルのコンパイラ・ ドライバ(CLI ドライバ)を提供している。 CLI ドライバは、コマンド文法 や基本的なオプションの意味について、 gcc と多くの共通点を持っている。
ユーザ ┏━━━━━━┓┏━━━━━━━┓┏━━━━━━━┓ 記述層 ┃ドライバ実装┃┃ドライバU/I┃┃サフィクス規則┃ ┗━━━━━━┛┗━━━━━━━┛┗━━━━━━━┛ ┏━━━━━━━━━┓ ┏━━━━━━━━━━━━┓ API層┃ トレースAPI ┃ ┃ コンパイル仕様API ┃ ┃ 警告API ┃ ┃ ┃ ┗━━━━━━━━━┛ ┗━━━━━━━━━━━━┛ ┏━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ エンジン ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━┛ 図1 COINS コンパイラ・ドライバのフレームワークユーザは、次の3種類のものを(必要ならば)準備する。
クラス coins.driver.Driver は、図1で言うところの「ドライバ実装」で あり、クラス coins.driver.CommandLine が「ドライバ U/I」である。
java [java-option ...] coins.driver.Driver [option | filename]...コマンド名の「java」は、環境によっては、「jre」などの別の名前かもし れない。 java-option には、 java 実行環境に対する適切なオプションを指定できる。
COINS を使用するためには、 COINS をビルドしたディレクトリに対して java のクラスパスが通っている必要がある。 CLASSPATH 環境変数か、または、 -cp オプションを適切に設定しなければならない。 例えば、 /usr/local/coins にビルドしたのであれば、
java -cp /usr/local/coins coins.driver.Driver [option | filename]と指定すれば良い。
-coins:optionsoptions にはコンマ記号 (`,') を含まない任意の文字列を指定できる。 複数の COINS オプションは、コンマ記号 (`,') で区切って連続して与えることができる。例えば、
-coins:debug,trace=Driver.8,suffix=/tmp/mysuffixesは、下記と同等である。
-coins:debug -coins:trace=Driver.8 -coins:suffix=/tmp/mysuffixesCOINSオプションには、上記の例の"debug"のように名前だけからなるものと、 "trace=Driver.8"のように"name=spec"の 形のものがある。後者の形で複数個のspecを指定する場合は、
name=spec1/spec2/spec3のようにそれらを"/"で区切って並べる必要がある。なお、上記の"suffix"オプションの "/"はこれとは違ってディレクトリの区切りを示すものである。
-coins:trace=HIR.1,trace=Driver.8のようにすると、最後の"trace=Driver.8"だけが有効になる。両方を有効にするためには
-coins:trace=HIR.1/Driver.8のように指定しなければならない。
標準的な(CLI ドライバまたはドライバ API によって解釈される)COINS オプションには下記のものがある。
-coins:target=archまたは
-coins:target=arch-conventionこのオプションは、 -b archまたは、-b arch-conventionを指定するのと完全に同等である。 最初の形の指定は
-coins:target=arch-standardを指定するのに等しい。また2番目の指定は
-coins:target-arch=arch,target-convention=conventionを指定するのに等しい。
-coins:assembler=assembler-commandおよび
-coins:linker=linker-commandが使用できる。
ターゲットアーキテクチャの種別を指定するオプションは次の形である。
-coins:target-arch=arch
現在は、arch には、次のいずれかを指定できる。
ターゲットアーキテクチャのコンベンションを指定するオプションは次の形である。
-coins:target-convention=convention
現在は、 target-arch=arch の値に応じて、次のいずれかを指定できる。
-coins:hirOpt=hiroptspec -coins:hirOpt=hiroptspec/hiroptspec/...hiroptspec は、次のいずれかである。
これらの最適化の意味については、6.1 基本最適化を参照されたい。
-coins:mdf,hir2c=opt詳しくは、6.3 粗粒度並列化コンパイラCoCoを参照されたい。
java coins.lparallel.LoopPara -coins:hir2c foo.cこれによって、OpenMP指示文を付加したCファイルが生成される。 詳しくは、 英語のドキュメントの6. Parallelization for HIRを参照。
-coins:ssa-opt=ssa_opt -coins:ssa-opt=ssa_opt/..ssa_opt は、次のいずれかである。
-coins:loopinversion無条件ジャンプで終るループを条件ジャンプで終るように上下を入れ換える。
-coins:target=x86simd,simd詳しくは、 7.2. SIMD並列化を参照されたい。
-coins:schedule,attach=coins.backend.sched.Schedule命令スケジューラをマシン命令選択後のレジスタ割り付け前とレジスタ割り付け後の 2ヶ所で起動する。 より詳しくは、8.2.3. 命令スケジューラを参照されたい。
-coins:regpromote
通常はメモリに割り付けられている大域変数をレジスタに割り付ける、 簡単なレジスタプロモーションの機能を起動する。
より詳しくは、8.2.5. レジスタ・プロモーションを参照されたい。
-coins:snapshotというオプション指定をする必要がある。その結果、xmlファイルが生成されるので、 それをCoVisで開けば良い。なお、CoVisでのグラフ表示にはATTの研究所で開発されたgraphviz というソフトを使っている。詳しくはCoVisUsersGuide.pdfを参照されたい。
-coins:debuginfo,trace=xxxのようなオプション指定をする必要がある。その出力結果を
java coins.driver.Driver -coins:debuginfo,... > trace.java perl trace2html.pl -o trace -c trace.javaのようにperlのファイルtrace2html.plで処理すればtrace.htmlファイルが 作成されるので、それをブラウザで表示すれば良い。
traceオプションの指定の仕方は以後の記述の中にあるが、バックエンドに関係する ものには以下のものがある。
ToCFG, ToLinear, ToMachineCode, EarlyRewriting, LateRewriting, Restruct, InstSel, AggregateByReference, ConvToAsm, NamingFloatConst, ReplaceFloatConst, RewriteConvUF, AugmentCFG, IntroVirReg, JumpCanon, JumpOpt, LoopInversion, PreHeaders, SimpleOpt, Ssa(pruned), Ssa(minimal), LiveRange, RegisterAllocation
上記の2つの可視化ツールの他に、以下のオプション指定がある。
level category.levellevel にはトレース・レベルを非負整数で、 category には トレース・カテゴリを英数字列で指定する。
-coins:trace=2は、メッセージ・レベルが 2 以下であるメッセージ・カテゴリなしトレース・メッセージを出力する。
-coins:trace=HIR.8は、メッセージ・レベルが 8 以下であるメッセージ・カテゴリが HIR のトレース・メッセージを出力する。 複数のトレース・カテゴリのないトレース・レベルが指定された場合、および、 同じトレース・カテゴリに対して複数のトレース・レベルが指定された場合、 後から指定された方が優先される。例えば、
-coins:trace=4/8は、メッセージ・レベルが 8 以下のメッセージ・カテゴリな しトレース・メッセージを表示する。 4 以下ではない。
-coins:trace=HIR.6/HIR.3の例では、メッセージ・レベルが 3 以下の、メッセージ・カテゴリが HIR のトレース・メッセージを表示する。 6 以下ではない。
-coins:trace=default.5/HIR.8は、メッセージ・レベルが 8 以下のメッセージ・カテゴリがDriver のトレース・メッセージと、メッセージ・レベルが 5 以下のメッセージ・カテゴリが HIR のものを除くトレース・メッセージを表示する。
java coins.driver.Driver -coins:hir2c=new foo.cは、 foo-hir-new.c というファイルを生成する。不正なタイ ミング指定子は無視され、ファイルは生成されない。
java coins.driver.Driver -coins:lir2c=new foo.cは、 foo-lir-new.c というファイルを生成する。不正なタイミング指定子は無視され、 ファイルは生成されない。
-coins:assembler=asコマンド名の中に空白文字が現れる場合、それは単語の区切 りとして扱われる。例えば、次のオプションは、プリプロセッサとして gcc を -E オプションつきで起動することを指定する。
-coins:preprocessor=gcc -Eこのとき、コマンド・インタプリタから空白文字をエスケー プすることを忘れてはならない。多くの Unix のシェルでは、 引用符を使って空白文字をエスケープできる。例えば下記は その例である。このうち、二重引用符を使う方法は Windows でも使用可能であろう。
-coins:preprocessor="gcc -E" -coins:preprocessor='gcc -E' '-coins:preprocessor=gcc -E'CLI ドライバは、コマンド名の中に引用符記号 (' および ") が現れる場合、その引用符記号と、その次に現れる同じ引用 符記号を文字列から取り除き、その間の文字列を、次のよう に解釈する。
-coins:preprocessor='my cc' -Eこの例では、プリプロセッサとして、プログラム `my cc' が、 `-E' というオプションつきで起動される。このとき、コマン ド・インタプリタから引用符記号や空白をエスケープするの を忘れてはならない。例えば、 Windows であれば、下記のよ うに二重引用符を使用する必要があろう。
-coins:preprocessor="'my cc' -E"CLI ドライバは、コマンド名の中に現れるバックスラッシュ 記号 (`\') に続く文字を、その文字そのものとして扱う。バックスラッシュ記号自身も、 バックスラッシュ記号に続けて記述することで、バックスラッシュ記号そのものとして記述で きる。引用符も、バックシュラッシュ記号に続けて記述する と、上述の意味を失い、引用符そのものとして解釈される。
-coins:linker=c:\\Program\ Files\\bin_utils\\ldこの例では、 `c:\Program Files\bin_utils\ld' がリンカと して使用される。ここで、もし必要なら、 `\' と空白を、コマンド・インタプリタからエスケープする のを忘れないように。例えば、 Windows であれば、下記のように二重引用符を 使用する必要があろう。
-coins:linker="c:\\Program\ Files\\bin_utils\\ld"
-coins:newOptionとすればよい。
if (ioRoot.getCompileSpecification().getCoinsOptions().isSet("newOption")) { // newOptionの処理 }とすればよい。
((coins.driver.CompileThread)Thread.currentThread()).getIoRoot()
でそれを得ることが出来る。
今までは、コンパイル時のオプション指定のつづりが間違っていてもそれのチェックはしなかった ので、単にその指定がなかったこととされ、思わぬエラーが発生することがあったが、 次にリリースされるCOINSのバージョンからは、coins.Registryに登録されていない名前を 指定した場合はウォーニング・メッセージを出力するようになる。
したがって、新しいオプションを追加するときはオプションの登録とチェック に記述されているような登録が必要になる。
各出力ファイルは、 -o オプションが指定されない限り、ソース・ファイル があるディレクトリに作られる。
これらはすべて等価であり、ひとつを指定することは他のすべてを指定する ことと等しい。
conventionが省略されると、 "standard" が指定されたものとみなす。
ターゲットアーキテクチャが指定されない場合のデフォルトは"sparc" である。
cygwin 上でコンパイルするユーザは、 -b x86-cygwin を指定するとともに、
(通常の場合は、)次を指定する必要がある。
-coins:assembler=as
その他、 cygwin のインストールの状況によって、下記を必要とするケースもあるようである。
-coins:preprocessor="cpp -I/usr/include"
java coins.driver.Driver foo.cは、 foo.c をコンパイルして a.out を生成する。
java coins.driver.Driver -o foo foo.cは、 foo.c をコンパイルして、実行形式ファイル foo を生成する。
java coins.driver.Driver -c foo.cは、 foo.c をコンパイルして、オブジェクト・ファイル foo.o を生成する。
java coins.driver.Driver -E foo/bar.c baz/boo.cは、 foo/bar.c と baz/foo.c をプリプロセスして、 foo/bar.i と baz/boo.i を生成する。ここで、 `.i' は、プリプロセスされた C プログラ ムのサフィクスとして、デフォルトのサフィクス規則に記述されている。
java coins.driver.Driver -S foo.c bar.iは、 foo.c と bar.i をコンパイルして、アセンブリ言語ファイル foo.s と bar.s を生成する
いくつかの例外的なケースを除き、 `java coins.driver.Driver' を `cc' に alias することで、 COINS C コンパイラを普通の C コンパイラと同様に使用 できる。例外的なケースとは、例えば、 `cc -E' は cpp とまったく同様には 使えない、などである。
今までは、コンパイル時のオプション指定のつづりが間違っていてもそれのチェックはしなかったので、 単にその指定がなかったこととされ、思わぬエラーが発生することがあったが、次にリリースされるCOINSのバージョンからは、 coins.Registryに登録されていない名前を指定した場合はウォーニング・メッセージを出力するようになる。
したがって、新しいオプションを追加するときはオプションの登録が必要になる。 (登録しなくても使うことは出来るが、ウォーニング・メッセージが出力される。) その登録は以下のように行えば良い。
そのオプション名をRegistry.javaの
public static final String OPTION[] = { };
の中に追加する。この配列はアルファベット順に並べてあるが、 最長一致検索が簡単にできるよう、先頭部分の同じ名前は 長い名前を先に書く。
そのオプション名をRegistry.javaの
public static final String COINS[] = { };
の中に追加する。この配列は辞書式順序に並べてあり、完全一致で調べる。
そのオプション名をそれぞれ、Registry.javaの
public static final String HIR_OPT[] = { }; public static final String SSA_OPT[] = { }; public static final String TRACE[] = { };
の該当するものの中に追加する。 これらの配列は辞書式順序に並べてあり、完全一致で調べる。
その名前を
public static final String ARCH[] = { };
の中に追加する。
それが
xxx=y1/y2/y3のような形であれば、Registry.javaに
public static final String XXX[] = { "y1", "y2", "y3", ... };のような文を追加するとともに、CheckOptionsのisCoinsOptionsAreCorrect()に
checkCoinsOptions("xxx", Registry.XXX);のような文を追加する。
CLI ドライバにおいては、 coins.driver.Driver クラスの main メソッド および go メソッドがドライバ U/I に相当する。これは次のように記述され ている。
protected void go(String[] args) {
CompileSpecification spec = new CommandLine(args);
int status = new CompilerDriver(spec).go(this);
System.exit(status);
}
public static void main(String[] args) {
new Driver().go(args);
}
coins.driver.CommandLine クラスは、 CLI ドライバのためのコンパイル仕様
クラスである。 coins.driver.CompilerDriver クラスが、エンジンである。
coins.driver.Driver クラスはドライバ実装も兼ねているので、自分自身をイ
ンスタンシエートしてエンジンに与えている。
もしも CLI ドライバと同じユーザ・インタフェースを持つドライバを作る
のであれば、この部分はそのまま使用できる。
CLI ドライバの場合は、 coins.driver.Driver クラスがドライバ実装の役 割を担っている。 CLI ドライバは上記の 4 種類のメソッドを提供しているが、 プリプロセス、アセンブル、リンクについては、外部プロセスを呼び出すだけ である。
ドライバ実装、および、そこから呼び出されるコンパイラ部品は、メッセー ジ・カテゴリ(文字列)と、メッセージ・レベル(非負整数)を指定して、ト レース・メッセージを出力する API を呼び出す。メッセージ・カテゴリは、 英数字列でありさえすれば、ユーザが任意に指定できる。
トレース・オプションには、トレース・カテゴリとトレース・レベルの対の 集合を指定できる。トレース API は、指定されたトレース・オプションに照 らして、いずれかのトレース・カテゴリと同じメッセージ・カテゴリを持ち、 そのトレース・レベル以下のメッセージ・レベルを持つトレース・メッセージ だけを出力する。
オペレータが指定したトレース・オプションを格納した coins.driver.Trace クラスのオブジェクトを取得するには、 CompileSpecification#getTrace() メソッドを使用する。
ドライバ実装、および、そこから呼び出されるコンパイラ部品は、警告カテ ゴリ(文字列)を指定して、警告メッセージを出力する API を呼び出す。警 告カテゴリは、ユーザが任意に指定できる。
警告オプションには、出力すべき警告カテゴリ、および出力すべきでない警 告カテゴリを指定できる。警告 API は、指定された警告オプションに照らし て、出力すべきと指定された警告メッセージだけを出力する。
CompileSpecification#getWarning() メソッドで、 coins.driver.Warning クラスのオブジェクトを取得できる。ここに、オペレータが指定した警告オプ ションが格納されている。
COINS ドライバ API は、コンパイラ部品に対して、ライブラリ・ディレク トリのパス名を提供する機能がある。すなわち、 CompileSpecification#getCoinsOptions() メソッドによって得られる coins.driver.CoinsOptions オブジェクトの CoinsOptions#getLibDir() メソッ ドを呼び出すことで得ることができる。 COINS のユーザは、オペレータに対 して、コンフィギュレーション・ファイルをライブラリ・ディレクトリに置く ように指示しておいて、上記 API を使ってディレクトリのパス名を得て、必 要なファイルを読み込むことができる。
COINS オプションである -coins:libdir=path が指定された場合、ドライバ API は、ライブラリ・ディレクトリのパス名として path を返す。このオプショ ンが指定されていない場合、オペレータのホーム・ディレクトリ (Java 実行 環境が返す、 user.home プロパティの値) に `coins' という名前のディレク トリがあれば、そのパス名を返す。それもない場合、カレント・ワーキング・ ディレクトリを示す相対パス名を返す。
デフォルトでは、ライブラリ・ディレクトリの下の `properties' というファ イルがプロパティ・ファイルとして参照される。
プロパティ・ファイルの位置は、オペレータが指定したいこともあるかもし れないので、コンパイル仕様を生成するときに設定できるようになっている。 プロパティ・ファイルの解釈と反映は、コンパイル仕様の生成の際に、 coins.driver.CoinsOptions クラスが行う。
properties ファイルの書式は、 java.utils.Properties#load() メソッド
が読み込めるものであれば良い。下記に記述例を示す。
debug:
trace: Driver.8
suffix: /tmp/mysuffixes
上記は、コマンドラインから次のように指定したのと同等である。
-coins:debug,trace=Driver.8,suffix=/tmp/mysuffixes
プロパティ・ファイルとコマンドラインの両方にオプション指定があった場合は、
前者のオプション指定の後ろに後者のオプション指定があった場合と同じことになる。
たとえば、両方にtraceオプション指定がある場合は、後者だけが有効になる。
デフォルトでは、ライブラリ・ディレクトリの下の `suffixes' というファ イルがサフィクス規則ファイルとして参照される。サフィクス規則ファイルが 見つからない場合は、下記の内容がデフォルトとして使用される。
#SRD, 2, Suffix rule DB file, format version 2
c, C, C source, i,s,o
c(out-newlir), C, C source, i,lir,-
i, C, preprocessed C source, -,s,o
cc/cpp/cxx/C, C++, C++ source, ii,s,o
ii, C++, preprocessed C++ source, -,s,o
java, Java, Java source, -,class,-
java(native), Java, Java source (native compile), -,s,o
f, FORTRAN, FORTRAN source, -,s,o
f(out-newlir), FORTRAN, FORTRAN source, -,lir,o
lir, LIR, new LIR, -,s,o
S, Assembler, assembly source (need preprocess), s,-,o
s, Assembler, assembly source, -,-,o
このファイルの文法の詳細は、 coins.driver.SuffixFactory.java に記述
されているが、おおむね、
サフィクス, 言語名, 意味, プリプロセス後/コンパイル後/アセンブル後のサフィクス
という構造になっている。
同じサフィクスを持つファイルであっても、コンパイラの動作モードに応じ て、異なるサフィクスのファイルに変換したい場合があり得る(例えば、ある Java コンパイラは、バイト・コードにコンパイルする場合は .class ファイ ルを、ネイティブ・コンパイルする場合は、 .o ファイルを生成するかもしれ ない)。このように、適用するサフィクス規則をコンパイラの動作時に変更し たい場合、サフィクス・オプションを使用できる。
サフィクス規則ファイルには、同じサフィクスに対して、複数の規則を定義 することができるが、その場合、そのうちのひとつを除いた残りの規則には、 それぞれに異なるサフィクス・オプションを与えなければならない。
コンパイル仕様にサフィクス・オプションが指定されなかった場合は、サフィ クス・オプションのないサフィクス規則が使用され、サフィクス・オプション が与えられた場合は、そのサフィクス・オプションと一致するサフィクス・オ プションを持つサフィクス規則が使用される。
サフィクス規則ファイルの位置は、オペレータが指定したいこともあるかも しれないので、コンパイル仕様を生成するときに設定できるようになっている。
サフィクス規則ファイルの解釈と反映は、コンパイル仕様の生成の際に、 coins.driver.SuffixFactory クラスが行う。
ライブラリディレクトリに settings という名前のファイルがあると、 coins.driver.Driver はこれを読み込み、 defaultSettings という Driver オブジェクトのメンバ変数に格納する。
settings ファイルの書式は、 java.utils.Propertis#load() メソッドが読 み込めるものであれば良い。
coins.driver.Driver にとって、 settings に記述して有効なのは、次のプ ロパティである。
COINS コンパイラインフラストラクチャが取り扱うターゲットアーキテクチャ 名と、リンカとして使用している gcc が取り扱うターゲットアーキテクチャ 名は異なるポリシーで命名されているので、正しく取り扱うには両者を変換 する必要があるが、現在その機能は実装されていない。 gcc コマンドのデ フォルトとは異なるアーキテクチャをターゲットとしようとするユーザは、 -coins:linker=linker-command オプションを用いて、リンカとして適切な オプションつきの gcc を起動するようにするなど、工夫する必要がある。