[go: up one dir, main page]
More Web Proxy on the site http://driver.im/

JP7295469B2 - 関数生成プログラム、関数生成方法、及び情報処理装置 - Google Patents

関数生成プログラム、関数生成方法、及び情報処理装置 Download PDF

Info

Publication number
JP7295469B2
JP7295469B2 JP2021569633A JP2021569633A JP7295469B2 JP 7295469 B2 JP7295469 B2 JP 7295469B2 JP 2021569633 A JP2021569633 A JP 2021569633A JP 2021569633 A JP2021569633 A JP 2021569633A JP 7295469 B2 JP7295469 B2 JP 7295469B2
Authority
JP
Japan
Prior art keywords
function
instruction
code
mnemonic
file
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Active
Application number
JP2021569633A
Other languages
English (en)
Other versions
JPWO2021140568A1 (ja
Inventor
健太郎 川上
盛幸 齋藤
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Fujitsu Ltd
Original Assignee
Fujitsu Ltd
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Fujitsu Ltd filed Critical Fujitsu Ltd
Publication of JPWO2021140568A1 publication Critical patent/JPWO2021140568A1/ja
Application granted granted Critical
Publication of JP7295469B2 publication Critical patent/JP7295469B2/ja
Active legal-status Critical Current
Anticipated expiration legal-status Critical

Links

Images

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F8/00Arrangements for software engineering
    • G06F8/30Creation or generation of source code
    • G06F8/31Programming languages or programming paradigms
    • G06F8/315Object-oriented languages
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F8/00Arrangements for software engineering
    • G06F8/40Transformation of program code
    • G06F8/51Source to source
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F8/00Arrangements for software engineering
    • G06F8/40Transformation of program code
    • G06F8/41Compilation

Landscapes

  • Engineering & Computer Science (AREA)
  • Software Systems (AREA)
  • General Engineering & Computer Science (AREA)
  • Theoretical Computer Science (AREA)
  • Physics & Mathematics (AREA)
  • General Physics & Mathematics (AREA)
  • Computing Systems (AREA)
  • Devices For Executing Special Programs (AREA)

Description

本発明は、関数生成プログラム、関数生成方法、及び情報処理装置に関する。
プログラムの実行速度を高速化する技術の一つとしてJIT(Just In Time)コンパイラ技術がある。JITコンパイラ技術とは、実行時に決定されるパラメータ、処理内容、及びプロセッサの状況に応じて、好適な機械語の命令列を生成する技術を言う。JITコンパイラ技術を用いて生成した機械語の命令列は、AOT(Ahead Of Time)型のコンパイラが生成する汎用的に処理可能な機械語の命令列からなる実行ファイルよりも処理が高速である。
但し、JITコンパイラ技術を使うためには、命令セットに含まれる命令ごとに、その命令を実行する機械語を生成する関数を開発者が自ら手作業でソースコードに記述する必要がある。よって、これらの関数を生成し、かつ各関数が正しい機械語を生成するかをテストする工数が膨大となる。
特開2000-56981号公報
一側面によれば、関数の作成に伴う工数を減らすことが可能な関数生成プログラム、関数生成方法、及び情報処理装置を提供することを目的とする。
一側面によれば、命令に関する命令情報を記憶した記憶部を参照して、前記命令に対応した関数であって、前記命令のオペランドを表す引数を受け取る第1の関数を生成する処理と、前記引数が表す前記オペランドに対して前記命令が行う処理を表す機械語を返す第2の関数を呼び出すコードを前記第1の関数の内部に生成する処理と、前記機械語をメモリに書き込むコードを前記第1の関数の内部に生成する処理と、をコンピュータに実行させるための関数生成プログラムが提供される。
一側面によれば、関数の作成に伴う工数を減らすことが可能となる。
図1は、実行可能プログラムを実行するターゲットマシンのハードウェア構成図である。 図2(a)は、AOT(Ahead Of Time)コンパイラ技術でコンパイルすることを前提としたC++の疑似ソースコードの一例を示す図であり、図2(b)は、パラメータqと配列in、outを宣言したC++のソースコードの一例を示す図であり、図2(c)は、配列Tblの初期値を宣言したC++の疑似ソースコードの一例を示す図である。 図3は、AOTコンパイラ技術で得られたアセンブリの疑似コードの模式図である。 図4は、AOTコンパイラ技術で得られた実行可能プログラムの動作について模式的に示す図である。 図5は、JITコンパイラ技術を使用する実行可能プログラムのC++の疑似ソースコードの一例を示す図である。 図6は、入力パラメータqが「8」の場合の、JITコンパイラ技術で生成した機械語の命令列と、それを逆アセンブルした疑似コードの模式図である。 図7は、実行時に呼び出す関数を、JITコンパイラ技術で実行時に生成する実行可能プログラムの動作について示す模式図である。 図8は、mov命令に対応したニーモニック関数の疑似ソースコードの例を示す図である。 図9は、第1実施形態に係る情報処理装置の動作を示す模式図である。 図10は、MachineCodeEmitter関数のC++の疑似ソースコードが記述されたソースファイルの一例を示す図である。 図11は、第1実施形態に係る情報処理装置の機能構成図である。 図12は、第1実施形態に係る関数生成方法について示すフローチャートである。 図13は、第1実施形態において、ニーモニック関数が記述されたソースファイルを利用した開発環境について示す模式図である。 図14は、C++のマクロを使用しないで生成した実行可能プログラムを実行するときのメモリの内容を示す模式図である。 図15(a)は、第1実施形態に係る第1の生成部がC++のマクロとしてニーモニック関数movを記述したソースコードの一例を示す図であり、図15(b)は、マクロを使用した場合において、実行可能プログラムを実行するときのメモリの内容を示す模式図である。 図16は、ニーモニックが同一で機械語が相違する命令について示す図である。 図17(a)は、ニーモニック「STRpost」、「STRpre」を採用した場合の第1実施形態の命令情報を模式的に示す図であり、図17(b)は、この命令情報に基づいて第1実施形態に従って生成したニーモニック関数について示す図である。 図18は、第2実施形態で使用する命令情報について模式的に示す図である。 図19(a)~(e)は、第2実施形態においてオペランドの型を定義するC++の疑似ソースコードの例について示す図である。 図20(a)は、ニーモニック「STRpost」に対応した第2実施形態に係るニーモニック関数STRのC++の疑似ソースコードが記述されたソースファイルの模式図であり、図20(b)は、ニーモニック「STRpre」に対応した第2実施形態に係るニーモニック関数STRのC++の疑似ソースコードが記述されたソースファイルの模式図である。 図21(a)は、ニーモニック関数の引数をOperand型とした場合のニーモニック関数movのC++の疑似ソースコードを示す図であり、図21(b)は、このニーモニック関数movを利用して開発者が記述したアプリケーションプログラム用のソースファイル41のC++の疑似ソースコードを示す図である。 図22(a)は、第2実施形態で生成したニーモニック関数movのC++の疑似ソースコードが記述されたソースファイルの模式図であり、図22(b)は、このニーモニック関数movを利用して開発者が記述したアプリケーションプログラム用のソースファイルのC++の疑似ソースコードの例を示す図である。 図23は、第2実施形態に係る関数生成方法について示すフローチャートである。 図24(a)は、第2実施形態に従って生成したニーモニック関数movのC++のソースコードが記述されたソースファイルの例を示す図であり、図24(b)は、このニーモニック関数movを利用して開発者が記述したアプリケーションプログラム用のソースファイルのC++の疑似ソースコードの例を示す図である。 図25は、第3実施形態で使用する命令情報について模式的に示す図である。 図26は、mov命令に対応した第3実施形態に係るニーモニック関数movが記述されたソースファイル34のC++の疑似ソースコードの例について示す模式図である。 図27は、第3実施形態に係るニーモニック関数movを利用して開発者が記述したアプリケーションプログラム用のソースファイルのC++の疑似ソースコードの例を示す図である。 図28は、第3実施形態に係る関数生成方法について示すフローチャートである。 図29(a)、(b)は、第4実施形態において、add命令の文法について示す図である。 図30は、第4実施形態に係る命令情報を模式的に示す図である。 図31は、第4実施形態に従って制御部が生成したニーモニック関数ADDのソースコードの一例を示す図である。 図32は、関数「SET()」を定義するC++の疑似ソースコードを模式的に示す図である。 図33は、第4実施形態において開発者がC++で記述したアプリケーションプログラム用のソースファイルの疑似ソースコードを模式的に示す図である。 図34は、出力例を示す図である。 図35は、第4実施形態に係る情報処理装置の機能構成図である。 図36は、第4実施形態において制御部が生成したニーモニック関数ADDのC++の疑似ソースコードを示す模式図である。 図37は、第4実施形態において第4の生成部が生成する関数「SET()」のC++の疑似ソースコードの一例を示す図である。 図38は、第4実施形態において定義ファイル生成部が生成した定義ファイルの疑似ソースコードを示す模式図である。 図39は、第4実施形態において開発者が記述したアプリケーションプログラム用のソースファイルのC++の疑似コードを示す図である。 図40は、第4実施形態に係る開発環境について示す模式図である。 図41は、第4実施形態における出力例を示す図である。 図42は、第4実施形態の別の例に係るソースファイルのC++の疑似ソースコードの例を示す模式図である。 図43(a)、(b)は、マクロで置換される関数の最後に可変引数マクロを記述したときに生じる不都合について模式的に示す図である。 図44は、第4実施形態に係る定義ファイルの生成方法について示すフローチャートである。 図45は、第1~第4実施形態に係る情報処理装置のハードウェア構成図である。
本実施形態の説明に先立ち、本願発明者が検討した事項について説明する。
前述のようにJITコンパイラ技術はプログラムの実行速度の高速化に有用である。このようなJITコンパイラ技術の利点について、AOT(Ahead Of Time)コンパイラ技術と比較しながら説明する。なお、このJITコンパイラ技術は、プロセッサに依存しない中間言語のコードをプロセッサが直接扱える機械語の命令列に実行時に変換する技術ではなく、実行時に決定されるパラメータ等に適した機械語の命令列を生成するコンパイラ技術である。
図1は、AOTコンパイラ技術やJITコンパイラ技術により生成された実行可能プログラムを実行するターゲットマシンのハードウェア構成図である。
このターゲットマシン1は、サーバやPC(Personal Computer)等の計算機であって、プロセッサ2とメモリ3とを有する。
このうち、プロセッサ2は、算術演算や論理演算を行うALU(Arithmetic and Logic Unit)等の計算コア4とレジスタファイル5とを備える。レジスタファイル5は、インデックスn(=0,1,2,…)で識別される複数の汎用のレジスタRnを備えたハードウェアである。
一方、メモリ3は、実行可能プログラムが展開されるDRAM(Dynamic Random Access Memory)等の揮発性メモリである。その実行可能プログラムは、以下のようにAOTコンパイラ技術を用いてソースコードをコンパイルすることにより生成することができる。また、JITコンパイラ技術で実行可能プログラムが呼び出す機械語の命令列を実行中に動的に生成してもよい。
図2(a)は、AOTコンパイラ技術でコンパイルすることを前提としたC++の疑似ソースコード10の一例を示す図である。
AOTコンパイラ技術では、開発者はC言語やC++の文法に即してソースコードを記述し、そのソースコードをGCC(GNU Compiler Collection)等のコンパイラが機械語の命令列にコンパイルする。
図2(a)の例では、処理10aにおいて配列「Tbl」の各要素をパラメータ「q」で除する。そして、処理10bにおいて、配列「in」の要素を配列「Tbl」の要素で除し、それを配列「out」に格納する。
図2(b)は、パラメータ「q」と配列「in」、「out」を宣言したC++の疑似ソースコード11の一例を示す図である。
パラメータ「q」は、前述の処理10aにおける除数であり、以下では入力パラメータとも呼ぶ。また、配列「in」と配列「out」は、それぞれ処理10bにおける入力データと出力データである。これらの配列「in」、「out」に格納するデータは特に限定されない。ここでは16個の画素データからなる画像を1000000枚格納する二次元配列として配列「in」と配列「out」を宣言する。
図2(c)は、配列Tblの初期値を宣言したC++の疑似ソースコード12の一例を示す図である。
配列「Tbl」は、画素データを量子化する量子化テーブルの値を格納する配列である。ここでは、各配列「in」、「out」に対応した16個の要素を持つ配列として配列「Tbl」を宣言する。そして、配列「Tbl」の各要素の初期値は2のべき乗であると仮定する。
図2(a)~図2(c)のソースコード10~12は全てC言語やC++の文法に即して開発者が記述し、コンパイラによってアセンブリに変換される。
図3は、AOTコンパイラ技術で前述のソースコード10をコンパイルして得られたアセンブリ14の疑似コードの模式図である。
そのアセンブリ14には、プロセッサ2の命令セットに含まれる複数の命令が、各処理10a、10bに対応して生成されている。
例えば、処理10aはmov命令からjmplt命令に至る6個の命令で実現され、処理10bはmov命令からjmplt命令に至る10個の命令で実現される。これらの命令は、プロセッサ2の命令セットに含まれる命令であって、オペランドとして記述されたレジスタやメモリに対して種々の操作を行う。なお、ここでは図1と同様にレジスタをRn(n=0,1,2,…)で表し、命令の位置を表すラベルをLm(m=0,1,2,…)で表す。そして、最初にレジスタR2に入力パラメータ「q」が保存されているものとする。
また、命令セットに含まれる全ての命令は、ニーモニックと呼ばれる名前で一意に識別される。例えば、mov命令のニーモニックは「mov」であり、store命令のニーモニックは「store」である。
アセンブリ14においては、命令のニーモニックの後ろにオペランドを記述するという文法が採用される。例えば、「mov R0, #0」は、即値である「0」をレジスタR0に格納する命令である。また、「load R1, [Tbl[R0]]」は、メモリ3上に値が保持されている配列「Tbl」のa番目の要素(aはレジスタR0の内容)の値をレジスタR1にロードする命令である。
一方、「store [Tbl[R0]], R1」は、レジスタR1の内容を、メモリ3上に値が保持されている配列「Tbl」のb番目の要素(bはレジスタR0の内容)に格納する命令である。また、「div R1, R1, R2」は、レジスタR1の内容をレジスタR2の内容で除し、その値をレジスタR1に格納する命令である。そして、「jmplt R0, #16, L0」は、レジスタR0の内容が即値の「16」未満の場合にラベルL0にジャンプする命令である。
ここで、処理10bにおける命令「div R2, R2, R1」について考える。この命令は、ソースコード10の処理10bにおける「in[i]/Tbl[i]」に相当する命令である。除数の「Tbl[i]」は、ソースコード10の処理10aにおいて入力パラメータ「q」で除されている。上記の命令「div R2, R2, R1」は入力パラメータ「q」の値の如何を問わずに正しい除算の結果を与える命令である。したがって、アセンブリ14は、どのような入力パラメータ「q」に対しても正しい結果を与える汎用的なコードとなっている。
しかしながら、div命令のような除算を行う命令は、どのような種類のプロセッサであっても、他の命令と比較して実行サイクル数が多い命令である。したがって、実行開始してからその結果が得られるまでのスループットが大きく、処理性能の低下を招いてしまう命令である。プロセッサ2の種類にもよるが、div命令以外の数値演算命令の実行サイクル数は1~5であるのに対し、div命令の実行サイクル数は80程度もあることがある。更に、深層学習や画像処理等ではforループのループの回数が膨大となるため、そのforループの内側にあるdiv命令によってスループットの低下が更に顕著となる。
このようなアセンブリ14をアセンブラが機械語の命令列に翻訳することにより機械語からなる実行可能プログラムが生成されることになる。LLVMのようにコンパイラの種類によっては、プロセッサ2の種類によらず、仮想的な命令セットを持つプロセッサ向けのアセンブリを生成することがある。この場合、このアセンブリを個別のプロセッサ向けの機械語の命令列に変換することもあるが、div命令のような除算命令があるとスループットが低下する点は同じである。
図4は、AOTコンパイラ技術で得られた実行可能プログラムの動作について模式的に示す図である。
図4に示すように、実行可能プログラム15は、入力データである配列「in」の各要素と入力パラメータ「q」の入力を受け付ける。そして、前述のように入力パラメータ「q」や配列「in」の値の如何を問わずに、実行可能プログラムは同一のアセンブリ14から得られた機械語の命令列により処理を行い、その処理の結果を配列「out」の各要素に格納する。
次に、スループットの低下を抑制し得るJITコンパイラ技術を前提としたプログラムについて説明する。
図5は、JITコンパイラ技術を使用する実行可能プログラムのC++の疑似ソースコード16の一例を示す図である。
このソースコード16は、その実行結果が図2(a)のソースコード10の実行結果と同一になるように開発者によって記述されたコードであって、処理16aと処理16bとを有する。このうち、処理16aは、ソースコード10の処理10aと同様に、配列「Tbl」の各要素をパラメータ「q」で除する処理である。また、処理16bは、ソースコード10の処理10bと同様に、配列「in」の要素を配列「Tbl」の要素で除してそれを配列「out」に格納する処理である。
その処理16bには、関数名がニーモニックと同一の「mov(R0, i)」等の関数が開発者によって記述される。関数「mov(R0, i)」は、言わばアセンブリ「mov R0, #i」に対応した関数であって、「mov R0, #i」が行う処理を表す機械語をメモリ3に書き込む関数である。なお、アセンブリ中では変数は記述することができず、「mov R0, #5」や「mov R0, #-128」など、アセンブリの時点では固定の値しか指定することができない。JITコンパイラ技術を用いた場合、即値に変数iが使用できる。このことはJITコンパイラ技術の利点の1つである。このように関数名が命令のニーモニックと同一であり、かつその命令が行う処理を表す機械語をメモリ3に書き込む関数のことを以下ではニーモニック関数と呼ぶ。
処理16bは、i=0~15に対してin[i]/Tbl[i]を実行する機械語の命令列をメモリ3に書き込む処理を実行する記述である。この例では開発者がswitch文を記述したことにより、除数である配列要素「Tbl[i]」の値に応じて異なるニーモニック関数を使って機械語の命令列が生成される。
例えば、「Tbl[i]」の値が「1」の場合には、「in[i]」に対する除数が「1」となるため、「in[i]」に対して何も行う必要がない。よって、この場合は、「case 1」において「in[i]」の値が格納されているレジスタR1の値に対して演算する機械語の生成は行わず、そのままout[i]へ値を格納する機械語をメモリ3に書き込むのみである。
一方、「Tbl[i]」の値が「2」の場合には、「case 2」においてshiftR命令の機械語の生成に対応した「shiftR(R1, R1, #1)」を実行する。このニーモニック関数は、レジスタR1の内容を1ビットだけ右にシフトし、その結果をレジスタR1に書き込む処理を表す機械語をメモリ3に書き込む関数である。よって、「shiftR(R1, R1, #1)」を実行することにより、レジスタR1に格納されている「in[i]」を2で除したのと等価な処理を行う機械語をメモリ3に書き込むことができる。
また、「Tbl[i]」の値が「4」の場合には、「case 4」において「shiftR(R1, R1, #2)」を実行する。これにより、レジスタR1の内容が右に2ビットだけシフトし、レジスタR1に格納されている「in[i]」を4で除したのと等価な処理を行う機械語をメモリ3に書き込むことができる。このように、除数が2のべき乗の値の場合には、shiftR命令に対応するニーモニック関数が実行される。
そして、「Tbl[i]」の値が「1」、「2」、「4」のような2のべき乗ではない場合には、「default」において「div(R1, R1, R2)」を実行する。このニーモニック関数は、div命令に対応した関数であって、レジスタR1の内容をレジスタR2の内容で除した値をレジスタR1に書き込む機械語をメモリ3に書き込む関数である。
このようなソースコード16によれば、「Tbl[i]」の値が「1」、「2」、「4」のような2のべき乗である場合には、div命令よりも実行サイクル数が少ないshiftR命令に等価な機械語や何もしない機械語がメモリ3に書き込まれる。そして、「Tbl[i]」の値が「1」、「2」、「4」のような2のべき乗でない場合にのみdiv命令に等価な機械語がメモリ3に書き込まれる。
JITコンパイラ技術では、このように「Tbl[i]」等のパラメータの値に応じて実行サイクル数を低減するのに最適な機械語を書き込むことにより、AOTコンパイラ技術と比較してプログラムの実行速度を高速化することができる。
図6は、ソースコード16をコンパイルして得られた実行ファイルの実行中に、処理16bがメモリにどのような機械語の命令列を書き込んだかを示す模式図である。なお、その実行ファイルを実行する際、入力パラメータqに「8」を与えている。また、図6では、この機械語の命令列を逆アセンブルしたアセンブリ17の疑似コードも併記している。
図6に示すように、q=8の場合には、配列「Tbl」の各要素が先頭から順に「1」、「2」、「4」となる。よって、処理16bのforループ実行に際して、i=0(case 1)、i=1(case 2)、i=2(case 4)の各場合に対応したshiftR関数とstore関数の各々が生成する機械語18がメモリ3内に配置されることになる。そして、その機械語18を逆アセンブルしたコードは、アセンブリ17におけるコード17a、17b、17cとなる。
図7は、実行時に呼び出す関数を、JITコンパイラ技術で実行時に生成する実行可能プログラムの動作について示す模式図である。ここでは、JITコンパイラ技術を用いたソースコード16をコンパイルして得られた実行可能プログラム20の動作について説明する。
図7に示すように、実行可能プログラム20は、まず入力パラメータ「q」の入力を受け付ける(ステップP10)。次いで、実行可能プログラム20は、その入力パラメータ「q」の値に応じて、処理が高速になる機械語18を生成する(ステップP11)。前述の図6の例では、「Tbl[i]」の値に適した機械語18が生成される。
続いて、実行可能プログラム20は、入力データである配列「in」の各要素の入力を受け付けて(ステップP12)、処理の結果を配列「out」の各要素に格納する(ステップP13)。
このとき、機械語18の中にはスループットの遅いdiv命令が含まれていないため、アセンブリ14に対応する実行可能プログラムよりも高速な処理を行うことができる。しかも、このように入力パラメータ「p」の値に応じて適切な機械語18を生成することにより、JITコンパイラ技術ではAOTコンパイラ技術よりもプログラムの実行速度を高速化できる。
ところで、このようなJITコンパイラ技術で使用するニーモニック関数はC++やC言語等のライブラリには存在しない関数であるため、開発者が予め手作業でニーモニック関数を記述しておく必要がある。
図8は、mov命令に対応したニーモニック関数のC++の疑似ソースコードの一例を示す図である。
このソースコード21は、ニーモニック関数movを定義するためのソースコードである。そのニーモニック関数movの関数名は、mov命令のニーモニック「mov」と同じであり、かつ引数はmov命令がとる「オペランド0」と「オペランド1」の二個である。
ニーモニック関数movの内部には、mov命令の処理を表す機械語をメモリ3に書き込むコードが記述される。ここでは、命令長は32ビットであり、mov命令のオペコードは8ビットで「0x01」であるとする。この場合、開発者は、変数「mnemonic」にオペコードの「0x01」を代入する文「unsigned mnemonic = 0x01;」をニーモニック関数movの本体に記述する。同様に、開発者は、変数「op0」、「op1」の各々に「オペランド0」、「オペランド1」を代入する文「unsigned op0 = オペランド0;」、「unsigned op1 = オペランド1;」をニーモニック関数movの本体に記述する。
そして、これらの文の後に、開発者は、「write((mnemonic<<24)+(op0<<16)+(op1<<8));」という文を記述する。関数writeは、引数のビット列をメモリ3に書き込む関数である。この例では、「mnemonic」の値を左に24ビットだけシフトしたビット列と、変数「op0」の値を左に16ビットだけシフトした値と、変数「op1」の値を左に8ビットだけシフトした値とのビット和が関数writeの引数となる。このビット列においては、先頭の8ビットがmov命令のオペコードとなる。そして、そのオペコードの次の8ビットが変数「op0」のビット列であり、その次の8ビットが変数「op1」のビット列である。なお、アセンブリ17のshiftR R1, R1, #1等のようにオペランドを3つとる命令に対応するニーモニック関数では、最後の8ビットが3番目の変数「op2」のビット列である。
このようなニーモニック関数を記述するには、開発者は、命令セットの仕様書を参照して各命令のフォーマットを特定し、そのフォーマットに従って関数writeの引数にオペコードとオペランドの各々のビット列を記述する必要がある。
しかしながら、このように手作業でニーモニック関数を記述するのは極めて煩雑な作業であり、開発者の負担増を招いてしまう。また、ニーモニック関数が所望の機械語を正しくメモリ3に書き込む動作するかの検証作業も手作業で行う必要があるため開発者の負担が更に増してしまう。特に、命令セットに含まれる命令の個数が数百個から千個を超えるプロセッサ2もある。例えば、ARM社が仕様を策定しているARMv8-A architecture profileに従うプロセッサでは、オペランドのバリエーションが異なる同一名称の命令を異なる命令として扱うと、約1000種類もの命令がある。この場合には約1000種類ものニーモニック関数を開発者が自ら記述しなければならず、全ての命令に対応したニーモニック関数の記述と検証とを手作業で行うために膨大な工数が必要となる。
更に、命令セットは将来的に拡張されることがあり、その度にニーモニック関数の記述と検証をするのは煩わしさに耐えない。
以下に、ニーモニック関数を作成するための工数を減らすことが可能な各実施形態について説明する。
(第1実施形態)
本実施形態では、以下のようにして情報処理装置がニーモニック関数を自動的に生成する。
[全体構成]
図9は、本実施形態に係る情報処理装置の動作を示す模式図である。
この情報処理装置30は、ニーモニック関数を自動的に生成するツールである制御部31を備えたPCやサーバ等の計算機である。ニーモニック関数を生成するに際し、制御部31は、関数を生成するための命令情報33を参照する。
命令情報33は、各命令のニーモニックとオペランドの個数とを対応付けた情報であって、開発者によって予め作成される。命令情報33の各々の行はそれぞれ異なる命令に対応しており、例えば1行目はmov命令に対応し、2行目はload命令に対応する。
この例では、開発者が、一行目のmov命令のニーモニック「mov」を、mov命令のオペランドの個数「2」と対応付けて命令情報33に格納する。なお、オペランドの個数は命令によって異なり、例えばshiftR命令ではオペランドの個数は「3」となる。
その命令情報33は、情報処理装置30内の記憶部にファイルとして格納される。なお、ネットワークを介して情報処理装置30と接続された外部の記憶部に開発者が命令情報33を格納し、その記憶部を制御部31が参照してもよい。
制御部31は、命令情報33を一行ずつ読み込んで、その行にあるニーモニックに対応した関数名を有するニーモニック関数を生成する。その生成方法について一行目のニーモニック「mov」を例にして説明する。
まず、制御部31は、命令情報33の一行目を読み込むことにより、ニーモニック「mov」とこれに対応したオペランドの個数「2」とを取得する。
次いで、制御部31は、ニーモニック「mov」に対応した関数名のニーモニック関数をC++のソースファイル34に記述する。本実施形態ではニーモニックと関数名とを同名にする。そのため、制御部31は、関数名34aが「mov」のニーモニック関数をソースファイル34に記述することになる。なお、ソースファイル34に記述するプログラミング言語はC++に限定されず、制御部31がC言語やC#のソースコードをソースファイル34に記述してもよい。
また、そのニーモニック関数movは、命令情報33における個数「2」と同数の引数をとる。これにより、ニーモニック関数movのひな形である「void mov(Operand OP0,Operand OP1){}」という中身が空の関数が記述されることになる。なお、ニーモニック関数movは第1の関数の一例である。
また、「OP0」と「OP1」の各々は、mov命令のオペランドを表す引数である。ここでは、制御部31がソースファイル34にソースコード34bを記述することにより、オペランドを表す変数の型としてOperand型を定義する。そして、制御部31は、コードT1において「OP0」と「OP1」の各々をOperand型として宣言する。
Operand型は、メンバとして「type」と「value」とを有するクラスである。このうち、「type」には、レジスタや即値等のオペランドの種類が格納される。そして、「value」には、即値やレジスタのインデックス等の数値が格納される。なお、ソースファイル34とは別のソースファイルにおいてOperand型を定義してもよい。
続いて、制御部31は、ニーモニック関数movの内部にコードT2~T4を生成する。
コードT2は、先に取得した関数名「mov」を変数「nm」に代入する文である。なお、この例では変数「nm」に文字列である「mov」を代入しているが、関数名「mov」と整数値とを予め一対一に対応させておき、その整数値を変数「nm」に代入してもよい。
また、コードT3は、ニーモニック関数movが引数として受け取ったOperand型の「OP0」と「OP1」とを配列「oplist」に代入する文である。
そして、コードT4は、MachineCodeEmitter関数を呼び出し、そのMachineCodeEmitter関数の返り値を関数writeでメモリ3に書き込むコードである。MachineCodeEmitter関数は、変数「nm」と変数「oplist」とを引数として受け取り、変数「oplist」で表されるオペランドに対して変数「nm」で表される命令が行う処理を表す機械語を生成する関数である。なお、MachineCodeEmitter関数は、第2の関数の一例であって、プロセッサ2のアセンブラと共に作成された動作が検証済の関数である。
以上により、制御部31が、ニーモニック関数movを自動的に生成したことになる。
この後は、命令情報33の二行目以降に対しても制御部31が上記と同様の処理を行うことにより、関数名が「load」、「shiftR」、「add」等のニーモニック関数を自動で生成する。そして、制御部31が、プロセッサ2の命令セットに含まれる全ての命令に対応したニーモニック関数が記述されたソースファイル34をメモリ等の記憶部に出力する。
これにより、開発者が手作業でニーモニック関数を記述する手間がなくなり、ニーモニック関数を生成するための工数を低減できる。
更に、そのニーモニック関数の関数名は、開発者が慣れ親しんだ命令のニーモニックと同一となるため、開発者が関数名を覚える手間がなく、開発者にとって扱いやすいニーモニック関数を提供できる。
しかも、そのニーモニック関数の引数の個数は、命令のオペランドの個数に等しい。これにより、開発者が慣れ親しんだ「mov OP0 OP1」というアセンブリの文法に類似したコード「mov(OP0,OP1)」でニーモニック関数を呼び出すことができるため、開発者の利便性が向上する。
図10は、上記のMachineCodeEmitter関数のC++の疑似ソースコードが記述されたソースファイル43の一例を示す図である。そのソースファイル43は、アセンブラ自身のソースファイルの一部でもよい。
この例では、コードT5~T8によりMachineCodeEmitter関数の機能が実現される。このうち、コードT5は、変数「mnemonic」と変数「op0」、「op1」、「op2」、「op3」の各々を32ビットの符号無し整数として宣言する文である。
また、コードT6は、MachineCodeEmitter関数が引数として受け取った変数nmの内容に対応したオペコードを変数「mnemonic」に代入するコードである。例えば、変数「nm」で特定されるニーモニックが「mov」の場合には、mov命令のオペコード「0x01000000」が変数「mnemonic」に代入される。
そして、コードT7は、変数「nm」の内容に応じて変数「OP0」、「OP1」の各々に対してビット操作を行うことにより、命令の仕様で定められたビット位置にこれらの変数を位置させるコードである。例えば、mov命令の場合には、32ビットの内の17~24ビットに第1オペランドが位置し、8~16ビットに第2オペランドが位置する。そこで、mov命令の場合には、文「op0=OP0<<16」を実行することにより、32ビットの内の17~24ビットに変数「OP0」のビット列を位置させる。一方、変数「OP1」については、文「op1=OP1<<8」を実行することにより、32ビットの8~16ビット目に「OP1」のビット列を位置させる。なお、mov命令は第3オペランドをとらないため、文「op2=0」により変数「op2」を「0」にする。
更に、コードT8は、各変数「mnemonic」、「op0」、「op1」、「op2」の各々を上位ビットから順に連結したビット列を生成し、それを返り値として返す文である。そのビット列は、変数「oplist」で特定されるオペランドに対して変数「nm」で特定される命令が行う処理を表す機械語である。
以上説明した関数生成方法によれば、制御部31が、命令情報33に基づいてニーモニック関数の内部にMachineCodeEmitter関数を呼び出すコードを生成する。MachineCodeEmitter関数は、引数「nm」で表される命令が、引数「oplist」で表されるオペランドに対して行う処理を表す機械語を生成する関数である。そのため、ニーモニック関数の作成に際し、命令の仕様書を基にして開発者が手作業で機械語を生成するコードを記述する必要がなくなり、ニーモニック関数を作成するのに要する工数を減らすことができる。
プロセッサ2(図1参照)を開発する際には、そのプロセッサ2で動作する機械語の実行ファイルを生成するためのツール群も開発される。そのツール群には、C言語やC++言語で記述されたソースファイルをアセンブリ言語に変換するためのコンパイラや、アセンブリ言語を機械語に変換するためのアセンブラが含まれる。そのようなツール群としては、例えばLLVMがある。MachineCodeEmitter関数は、LLVMのアセンブラに内蔵されている関数であり、アセンブラを開発した際にその動作が検証されて提供されている。そのため、本実施形態では、制御部31が生成したニーモニック関数が正しい機械語を生成しているかという動作検証を行う必要がない。これにより、ニーモニック関数を作成する工数に加え、ニーモニック関数の動作検証に要する工数も低減でき、ニーモニック関数の作成に伴う工数を低減することができる。
なお、本実施形態ではLLVMの中に含まれるMachineCodeEmitter関数を例に説明したが、本実施形態はこれに限定されない。例えば、MachineCodeEmitter関数に代えて、LLVMとは別のツール群(例えばGCC)の中の機械語生成関数を呼び出すようにニーモニック関数を生成してもよい。機械語生成関数は、MachineCodeEmitter関数と同等の機能を有する関数である。この場合は、制御部31は、図9の各変数「mov」、「OP0」、「OP1」をその機械語生成関数の引数の個数や型に変換するようなコードを各コードT2、T3に代えてソースファイル34に記述すればよい。
また、図9の例では、最大で三つの変数「OP0」、「OP1」、「OP2」を配列「oplist」にまとめてMachineCodeEmitter関数に渡すことができるが、各変数「OP0」、「OP1」、「OP2」を別々の引数として受け取る機械語生成関数もある。その場合には、制御部31は、コードT3を生成せずに、各変数「OP0」、「OP1」、「OP2」のそれぞれを別々の引数として機械語生成関数に渡すようなコードを生成すればよい。
[機能構成]
次に、本実施形態に係る情報処理装置30の機能構成について説明する。
図11は、本実施形態に係る情報処理装置30の機能構成図である。
図11に示すように、情報処理装置30は、制御部31と記憶部32とを有する。
このうち、記憶部32は、HDD(Hard Disk Drive)等の記憶装置やDRAM等のメモリによって実現することができ、前述の命令情報33とニーモニック関数のソースファイル34とを記憶する。
また、制御部31は、情報処理装置30の全体を制御する処理部であり、第1の生成部36、第2の生成部37、第3の生成部38、及び出力部39を備える。
第1の生成部36は、命令情報33を参照して、各命令に対応したニーモニック関数を生成し、そのニーモニック関数をソースファイル34に記述する処理部である。一例として、第1の生成部36は、命令情報33からニーモニックを取得し、そのニーモニックと同じ関数名34a(図9参照)をニーモニック関数に付与する。また、第1の生成部36は、ニーモニック関数の引数として、命令情報33におけるオペランドの個数に等しい個数の引数を宣言する。
例えば、命令情報33におけるニーモニックが「mov」の場合には、第1の生成部36は、ニーモニック関数movとして「void mov(Operand OP0,Operand OP1){}」という関数を生成し、その関数のソースコードをソースファイル34に記述する。なお、第1の生成部36が記述したニーモニック関数の中身は空である。
また、第1の生成部36は、命令セットに含まれる全てのニーモニック関数を一つのソースファイル34に記述してもよいし、ニーモニック関数の各々を異なるソースファイルに記述してもよい。
一方、第2の生成部37は、前述のMachineCodeEmitter関数を呼び出すコードを生成し、そのコードをソースファイル34に記述する処理部である。MachineCodeEmitter関数の引数は、各オペランドに対応した変数である「oplist」と、命令に対応した変数である「mov」である。これらの引数を受け取ると、MachineCodeEmitter関数は、命令がオペランドに対して行う処理を表す機械語を生成する。
そして、第3の生成部38は、MachineCodeEmitter関数が生成した機械語をメモリ3に書き込むコードを生成し、そのコードをソースファイル34に記述する処理部である。そのコードは、例えば「write(MachineCodeEmitter(nm, oplist);」という書式になる。
出力部39は、第1~第3の生成部36~38が記述したソースファイル34を記憶部32に書き出す。
[処理の流れ]
図12は、本実施形態に係る関数生成方法について示すフローチャートである。
まず、第1の生成部36が、命令情報33を参照して、ニーモニックとこれに対応するオペランドの個数とを取得する(ステップS10)。
次いで、第1の生成部36が、中身が空のニーモニック関数を生成し、それをソースファイル34に記述する(ステップS11)。例えば、ニーモニックが「mov」の場合は、第1の生成部36は、「void mov(Operand OP0,Operand OP1){}」という中身が空のニーモニック関数をソースファイル34に記述する。なお、このニーモニック関数の引数の個数は、ステップS10で取得したオペランドの個数となる。
次に、第2の生成部37がMachineCodeEmitter関数を呼び出すコードを生成する(ステップS12)。例えば、第2の生成部37は、第1の生成部36が記述したニーモニック関数の内部に、MachineCodeEmitter関数を呼び出すコード「MaschineCodeEmitter(nm,oplist);」を記述する。
これと共に、第2の生成部37は、図9のコードT2、T3等のように、ニーモニック関数の引数の値をMachineCodeEmitter関数に渡すための文もソースファイル34に記述する。
続いて、第3の生成部38が、MachineCodeEmitter関数が生成した機械語をメモリ3に書き込むコードを生成する(ステップS13)。一例として、第3の生成部38は、関数writeの引数にMachineCodeEmitter関数を記述した「write(MachineCodeEmitter(nm, オペランドリスト));」というコードT4(図9参照)を生成し、それをソースファイル34に記述する。
そして、命令情報33に含まれる全ての行に対してステップS10~S13の処理を行う。その後、出力部39が、全てのニーモニック関数を含むソースファイル34を記憶部32に書き出す(ステップS14)。
以上説明した本実施形態によれば、第1~第3の生成部36~38の各々が命令情報33に基づいてニーモニック関数を自動的に生成する。そのため、開発者が手作業でニーモニック関数を記述する場合と比較して、ニーモニック関数を生成する際の工数を減らすことができる。
しかも、このように各生成部36~38がニーモニック関数を生成することで、開発者が手作業でニーモニック関数を記述する場合よりもバグの発生を抑制できる。その結果、バグのあるプログラムをターゲットマシン1で無駄に実行する時間が減り、ターゲットマシン1のハードウェア資源の無駄な消費を改善できる。
[開発環境]
開発者は、上記のようにニーモニック関数が記述されたソースファイル34を利用することにより、ターゲットマシン1のプロセッサ2で実行する様々なアプリケーションプログラムを開発することができる。そこで、そのアプリケーションプログラムの開発環境について以下に説明する。
図13は、ニーモニック関数が記述されたソースファイル34を利用した開発環境について示す模式図である。
この例では、情報処理装置30の内部に開発環境を構築する場合を想定する。その場合、ニーモニック関数を生成するツールである制御部31が命令情報33を参照し、図12のフローチャートに従って全てのニーモニック関数を含むソースファイル34を生成する。
一方、開発者は、例えばC++を用いてアプリケーションプログラム用のソースファイル41を作成する。そのソースファイル41は、JITコンパイラ技術の機能を使用することを前提としたファイルであって、C++のライブラリ関数に加えて、ソースファイル34にあるニーモニック関数を呼び出す記述を含む。
そして、開発者の指示の下で、コンパイラ、アセンブラ、及びリンカのプログラム群42がビルドを行う。このうち、コンパイラには、例えば#defineで始まるディレクティブの処理を行うためのプリプロセッサが含まれる。そして、ビルドにおいては、プログラム群42に含まれるコンパイラがソースファイル41をコンパイルする。
このとき、コンパイラは、各ソースファイル34、41、43を読み込んでアセンブリの中間言語ファイルを出力する。これらのソースファイルのうち、ソースファイル43は、前述のMachineCodeEmitter関数が記述されたソースファイルである。そして、アセンブラがその中間言語ファイルを機械語の命令列に変換してオブジェクトファイルを生成する。
その後、リンカは、オブジェクトファイルと種々のライブラリとをリンクすることにより、プロセッサ2で実行可能なバイナリ形式の実行可能プログラム44を生成する。
なお、ここでは、前述のソースファイル43が、アセンブラ自身のソースファイルの一部であることを例にして説明した。アセンブラを開発するときの動作検証を通じて、ソースファイル43に記述されたMachineCodeEmitter関数の動作が正しいことは検証されている。
なお、機械語の生成ルールが秘匿されているようなCPUでは、アセンブラのソースファイルが公開されていないものの、実行ライブラリファイルが入手可能なこともある。その場合には、ソースファイル43に代えて機械語生成関数の機能を予め機械語の命令列に変換済みの実行ライブラリファイル43aを入力として用い、これをリンクすることにより実行可能プログラム44を生成すればよい。
以上により、アプリケーションプログラム用のソースファイル41から実行可能プログラム44を生成することができる。
その実行可能プログラム44は、JITコンパイラ技術によって、実行時のパラメータや環境に応じて最適な機械語の命令列を実行時に生成する。そのため、この実行可能プログラム44は、深層学習や画像処理等のようにループの回数が膨大で大規模な演算が必要なアプリケーションプログラムの高速化に特に有効である。同様に、動画圧縮等の画像処理、暗号化処理、復号処理、及びブロックチェーン技術等で使用するアプリケーションプログラムも高速化することができる。
なお、実行可能プログラム44の実行速度を更に速めるために、以下のようにC++のマクロとしてニーモニック関数を記述してもよい。
図14は、C++のマクロを使用しないで生成した実行可能プログラム44を実行するときのメモリ3の内容を示す模式図である。
この例では、開発者によってソースファイル41にニーモニック関数mov(OP0,OP1)が記述されている場合を想定している。この場合、命令を実行すべきアドレスがニーモニック関数mov(OP0,OP1)の呼び出し処理に対応する機械語が格納されたメモリアドレスに到達すると、関数呼び出しによってソースファイル34におけるニーモニック関数movが呼び出される。
関数呼び出しの処理は、処理前にレジスタR0、R1、…のデータをメモリ3に退避させたり、処理後にそのデータをレジスタR0、R1、…に復帰させたりするためオーバーヘッドが大きく、プログラム実行を遅くしてしまう。
一方、図15(a)は、第1の生成部36がC++のマクロとしてニーモニック関数movを生成したしたソースコード45の一例を示す図である。
図15(a)に示されるように、第1の生成部36は、ステップS11(図12参照)において、マクロ「#define」を用いてニーモニック関数movのマクロをソースファイル34に記述する。
また、図15(b)は、このようにマクロを使用した場合において、実行可能プログラム44を実行するときのメモリ3の内容を示す模式図である。
マクロを利用すると、コンパイル時にプリプロセッサがソースファイル41においてニーモニック関数mov(OP0,OP1)が記述された部分にソースコード45を展開する。そのため、関数呼び出しを行わなくても「mov OP0, OP1」を実行する機械語をメモリ3に書き込むことができ、実行可能プログラム44がJITコンパイル技術で機械語を生成する処理の実行速度を速めることが可能となる。
(第2実施形態)
命令セットの中には、ニーモニックが同一であるにも関わらず、機械語が相違する複数の命令が存在する場合がある。そのような相違を反映させるために、これらの命令ごとにニーモニック関数の関数名も変えてしまうと、開発者が覚えるべき関数名が増えてしまい、開発者の負担が増えてしまう。そこで、本実施形態では、ニーモニックが同一で機械語が相違する複数の命令が存在する場合でも開発者の負担増を抑制できる例について説明する。
まず、ニーモニックが同一で機械語が相違する命令について説明する。
図16は、そのような命令をアセンブリで記述した例について示す図である。
これらの命令51、52は、いずれもストア命令であって、そのニーモニックはいずれも「STR」で同一である。
このうち、命令51は、「アドレスレジスタ」に格納されているアドレスのメモリ3(図1参照)に「SRCレジスタ」の値を書き込み、その後、「アドレスレジスタ」に格納されている値を「即値」分だけインクリメントする命令である。
一方、命令52は、「アドレスレジスタ」に格納されている値を最初に「即値」分だけインクリメントし、インクリメントされた値のアドレスのメモリ3に「SRCレジスタ」の値を書き込む命令である。
このように、命令51、52は、「アドレスレジスタ」に格納されている値を「即値」分だけインクリメントするタイミングが相違しており、異なる処理を行う命令である。
例えば、命令51ではニーモニックに続く文字列が「SRCレジスタ、[アドレスレジスタ]、即値」となっているのに対し、命令52ではその文字列が「SRCレジスタ、[アドレスレジスタ、即値]!」となっている。アセンブラは、このような文字列の相違に基づいて両者を区別し、アセンブラ内部で命令51のニーモニックを「STRpost」と読み替え、かつ命令52のニーモニックを「STRpre」と読み替えている。
図17(a)は、これらのニーモニック「STRpost」、「STRpre」を採用した場合の第1実施形態の命令情報33を模式的に示す図である。
そして、図17(b)は、この命令情報33に基づいて、第1実施形態に従って生成したニーモニック関数について示す図である。
図17(b)に示すように、この場合は、命令51に対応するニーモニック関数STRpostと、命令52に対応するニーモニック関数STRpreが生成される。開発者は、関数名「STRpost」、「STRpre」を覚えておき、これらをアプリケーションプログラム用のソースファイルに記述することになる。
しかしながら、これらのニーモニック関数の元となる二つの命令はいずれもストア命令であるにも関わらず、このように関数名が異なると開発者が覚えるべき関数名が増えてしまい、開発者の負担が増加することになる。
そこで、本実施形態では、以下のようにしてニーモニック関数の関数名が増加するのを抑制する。
図18は、本実施形態で使用する命令情報33について模式的に示す図である。
図18に示すように、本実施形態に係る命令情報33においては、関数名、ニーモニック、オペランドの個数、及びオペランドの型が対応付けられて格納される。命令情報33の各々の行はそれぞれ異なる命令に対応しており、例えば1行目はmov命令に対応し、2行目はload命令に対応する。なお、第1実施形態と同様に、命令情報33は開発者によって予め作成される。
この命令情報33において、関数名は、ニーモニック関数の名前であって、各ニーモニックに対応した名前が格納される。なお、本実施形態では関数名とニーモニックとを一対一に対応させる必要はなく、ニーモニックにこだわらずに開発者が覚えやすい同一の関数名を複数のニーモニックに対応させてもよい。例えば、STRpost命令とSTRpre命令はいずれもストア命令であるため、これらの命令に対応した関数名はいずれも「STR」とする。
また、オペランドの個数は、第1実施形態と同様に、各命令がとるオペランドの個数である。
そして、オペランドの型は、命令のオペランドの種類を示す型のリストである。例えば、mov命令においては、第1オペランドはレジスタであり、第2オペランドは即値となる。本実施形態では、レジスタを示すRegister型と即値を示すImmediate型とを予め定義しておき、これらの型のリストをニーモニック「mov」に対応付けて命令情報33に予め格納する。なお、そのリストの第1成分は第1オペランドの型を示し、第2成分は第2オペランドの型を示す。また、三つのオペランドをとる命令においては、リストの第3成分は第3オペランドの型を示す。
ここで、C++の文法においては、二つの関数の関数名と引数の個数とが同一であっても、それらの引数の型が異なれば各関数を異なる関数として扱うことができる。
そこで、本実施形態では、二つのニーモニック関数STRの各々で引数の型を変えることにより、関数名と引数の個数とが同一であっても異なる処理を実現できるようにする。この例では、ニーモニック「STRpost」に対応したニーモニック関数STRの引数の型をRegister型とPostIncAddrReg型とする。そして、ニーモニック「STRpre」に対応したニーモニック関数STRの引数の型をRegister型とPreIncAddrReg型とする。
これにより、本実施形態に係る命令情報33においては、関数名が「STR」で同一であり、かつ、オペランドの型が異なる複数の相異なるニーモニック「STRpre」、「STRpost」が存在することになる。
なお、第1実施形態における命令情報33では、図17(a)のようにニーモニック「STRpost」のオペランドの個数が「3」であるのに対し、本実施形態では図18のようにその個数は「2」となる。これは、後述のようにPostIncAddrReg型には二つのメンバがあり、これらのメンバにSTRpost命令の第2オペランドと第3オペランドを格納することができるためである。同様に、PreIncAddrReg型も二つのメンバがあり、これらのメンバにSTRpre命令の第2オペランドと第3オペランドを格納できるため、「STRpre」に対応したオペランドの個数も「2」となる。
図19(a)~(e)は、オペランドの型を定義するC++の疑似ソースコードの例について示す図である。
図19(a)は、Register型を定義するソースコードの例である。Register型は、前述のようにレジスタを示す型である。ここでは、Register型を定義するクラスのクラス名を「Reg」とし、そのクラスのメンバを「regIndex」とする。「regIndex」は、レジスタのインデックスを格納する変数であり、例えば符号無し整数型として宣言される。
図19(b)は、AddrReg型を定義するソースコードの例である。AddrReg型は、アドレスレジスタを示す型である。AddrReg型を表すクラス「AddrReg」のメンバは、アドレスのベース値を保持するレジスタのインデックスを格納する「regIndex」と、アドレスオフセット値である即値を格納する「imm_value」である。なお、「imm_value」の初期値は0とする。
図19(c)は、PostIncAddrReg型を定義するソースコードの例である。
PostIncAddrReg型のクラスのメンバは、アドレスのベース値を保持するレジスタのインデックスを格納する「regIndex」と、命令実行後にアドレスのベース値をどれだけインクリメントするかを示す即値を格納する「imm_value」である。
図19(d)は、PreIncAddrReg型を定義するソースコードの例である。
PreIncAddrReg型のクラスのメンバは、アドレスのベース値を保持するレジスタのインデックスを格納する「regIndex」と、命令実行前にアドレスのベース値をどれだけインクリメントするかを示す即値を格納する「imm_value」である。
図19(e)は、Immediate型を定義するソースコードの例である。Immediate型は、前述のように即値を示す型である。この例では、Immediate型を定義するクラスのクラス名を「Imm」とし、そのクラスのメンバを「imm_value」とする。「imm_value」は、即値を格納する整数型の変数である。
図20(a)は、ニーモニック「STRpost」に対応したニーモニック関数STRのC++の疑似ソースコードが記述されたソースファイル34の模式図である。
このニーモニック関数STRのソースコードは、命令情報33に基づいて制御部31が次のように生成する。
例えば、命令情報33(図18参照)においてニーモニック「STRpost」に対応する関数名は「STR」であるから、制御部31はこのニーモニック関数の関数名53aを「STR」とする。
また、制御部31は、命令情報33を参照することによりニーモニック「STRpost」のオペランドの個数が「2」であることを特定し、コードT11において「OP0」と「OP1_2」の2個の変数を引数として宣言する。
更に、制御部31は、命令情報33を参照することによりニーモニック「STRpost」のオペランドの型がRegister型とPostIncAddrReg型であることを特定する。これに基づいて、制御部31は、コードT11において各変数「OP0」と「OP1_2」の各々の型をRegister型とPostIncAddrReg型として宣言する。
また、制御部31は、このニーモニック関数STRの内部においてコードT12~T15を生成する。
このうち、コードT12は、命令情報33のニーモニック「STRpost」を変数「nm」に代入する文である。また、制御部31は、命令情報33から特定したRegister型とPostIncAddrReg型に基づいて、MachineCodeEmitter関数の引数「oplist」に含める変数の個数を特定する。例えば、Register型はメンバ変数が一つであり、PostIncAddrReg型はメンバ変数が二つであるため、これらの型のメンバ変数の総数は三つとなる。そこで、制御部31は、三つのメンバに対応する三つのOperand型の変数「op0」、「op1」、「op2」を宣言するコードT13を生成する。このうち、変数「op0」は、Register型の変数「OP0」に対応する。また、変数「op1」、「op2」は、PostIncAddrReg型の変数「OP1_2」に対応した二つの変数である。なお、Register型、AddrReg型、PostIncAddrReg型、PostIncAddrReg型、及びImmediateの各々の型がそれぞれいくつのメンバ変数を有するかは、図19の各クラスを定義するソースファイルにおいて予め定義しておけばよい。
一方、コードT14は、ニーモニック関数STRが引数として受け取った変数「OP0」、「OP1_2」の各々を、MachineCodeEmitter関数の引数「oplist」の型に変換するコードである。
例えば、文「op0.type = REGISTER」により、変数OP0の型「Register」に対応した文字列「REGISTER」が変数op0のメンバ「type」に代入される。また、文「op0.value = OP0.regIndex;」により、変数OP0のメンバ「regIndex」が、変数op0のメンバ「value」に代入される。
同様に、文「op1.type = REGISTER;」と文「op1.value = OP1_2.regIndex;」は、PostIncAddrReg型の変数OP1_2をOperand型の変数op1に型変換をするための文である。そして、文「op2.type = IMMEDIATE_VALUE;」と文「op2.value = OP1_2.imm_value;」は、PostIncAddrReg型の変数「OP1_2」をOperand型の変数「op2」に型変換をするための文である。
更に、文「oplist={op0,op1,op2}」は、Operand型の配列「oplist」の各要素に上記の各変数「op0」、「op1」、「op2」を代入するコードである。その配列「oplist」は、コードT15においてMachineCodeEmitter関数に渡される。
コードT15は、MachineCodeEmitter関数を呼び出して、そのMachineCodeEmitter関数が生成した機械語を関数writeでメモリ3に書き込むコードである。
このようなソースコードによれば、ニーモニック関数STRが引数として受け取った変数「OP0」、「OP1_2」の各々がコードT14においてOperand型の配列「oplist」に変換される。そのため、MachineCodeEmitter関数の第2引数「oplist」の型に各変数「OP0」、「OP1_2」の型を合わせることができ、開発者が意図した機械語をMachineCodeEmitter関数が生成することができる。
図20(b)は、ニーモニック「STRpre」に対応した本実施形態に係るニーモニック関数STRのC++の疑似ソースコードが記述されたソースファイル34の模式図である。
図20(a)の例と同様に、このニーモニック関数STRのソースコードについても制御部31が命令情報33に基づいて生成する。なお、図20(a)と図20(b)では関数名がいずれも「STR」で同一となっているが、これらの関数の第2引数の型が相違するため、これらの関数はC++の文法上は別々の関数として区別されるため問題にはならない。
このように、本実施形態においては、関数名と引数の個数が同一でオペランドの型が異なる複数のニーモニックを命令情報33に格納することにより、これらのニーモニックから同じ関数名のニーモニック関数を生成できる。そのため、ニーモニック関数の関数名が増大するのを防止でき、開発者が覚えるべき関数名が増えるのを抑制することができる。
また、本実施形態では以下のようにデバッグが容易になるという利点も得られる。
図21(a)は、本実施形態とは異なり、ニーモニック関数の引数をOperand型という共通の型で表した場合のニーモニック関数movのC++の疑似ソースコード55を示す図である。この場合は、ニーモニック関数movの引数とMachineCodeEmitter関数の第2引数の型がいずれもOperand型であるため、本実施形態のような型変換のコードはニーモニック関数movの内部に記述されていない。
そして、図21(b)は、このニーモニック関数movを利用して開発者が記述したアプリケーションプログラム用のソースファイル41のC++の疑似ソースコードを示す図である。
開発者は、ソースファイル41における文「op0.type=REGISTER;」によって第1引数「OP0」がレジスタであることを意図しており、かつ文「op1.type=IMMEDIATE_VALUE」によって第2引数「OP1」が即値であることを意図している。また、ソースファイル41における文「mov(OP1,OP0);」は、図21(a)においてニーモニック関数movが引数として2つのOperand型の変数を受け付けるよう記述されているため、C++の文法上は問題がない。
しかし、ニーモニック関数movとMachineCodeEmitter関数は、mov命令の第1オペランドがレジスタであり、かつ第2オペランドが即値であることを前提として作成されている。これに対し、文「mov(OP1, OP0);」においては第1引数に即値を表す変数「OP1」が記述され、第2引数にレジスタを表す変数「OP0」が記述されている。文「mov(OP1,OP0);」は、C++の文法上は問題がないため、このような誤りがあってもコンパイル時にエラーが出ない。
よって、この場合には、コンパイル済みのプログラムを実行した後に、開発者がその出力で得られる結果が本来の結果と異なっていることを認識して初めてソースファイル41のソースコードの誤りに気付くことになる。また、結果がおかしいことに開発者が気付かなければ、そのまま正しい出力が得られているものとして開発者が誤りを見過ごしてしまうことになる。更に、仮に出力がおかしいことに開発者が気付いたとしても、ソースファイル41の記述行数が多い場合には、記述が誤っている箇所を開発者が特定するのに時間がかかり、デバックに長時間を要してしまう。
一方、図22(a)は、本実施形態で生成したニーモニック関数movのC++の疑似ソースコードが記述されたソースファイル34の模式図である。本実施形態では、ニーモニック関数movの引数の型は{Register型、Immediate型}となる。
そして、図22(b)は、このニーモニック関数movを利用して開発者が記述したアプリケーションプログラム用のソースファイル41のC++の疑似ソースコードの例を示す図である。
ここで、開発者が誤ってニーモニック関数movの第1引数と第2引数の各々の型を逆にしてしまい、「mov(imm,reg);」と記述したとする。この場合は、ソースファイル41におけるニーモニック関数movの呼び出し時の引数の型の順番が相違しているため、コンパイル時にコンパイラがエラーを出す。よって、図22(a)の例よりも早く開発者が間違いに気づくことができ、かつコンパイル時のエラーメッセージに基づいて間違いの箇所を特定するのが容易となる。
[処理の流れ]
次に、本実施形態に係る関数生成方法について説明する。
図23は、本実施形態に係る関数生成方法について示すフローチャートである。
まず、第1の生成部36が、命令情報33を参照して、相互に対応する関数名、ニーモニック、オペランドの個数、及びオペランドの型を取得する(ステップS20)。
次いで、第1の生成部36が、中身が空のニーモニック関数を生成し、それをソースファイル34に記述する(ステップS21)。そのニーモニック関数の引数の個数は、ステップS20で取得したオペランドの個数である。また、第1の生成部36は、ニーモニック関数の引数の型を、ステップS20で取得したオペランドの型に宣言するコードT11(図20(a)参照)を生成する。
次に、第2の生成部37が、ニーモニック関数が引数として受け取った変数の型を、MachineCodeEmitter関数の第2引数である配列「oplist」のOperand型に変換するコードを生成する(ステップS22)。例えば、第2の生成部37は、図20で説明したコードT14を生成し、それをニーモニック関数の内部に記述する。
次いで、第2の生成部37がMachineCodeEmitter関数を呼び出すコードを生成する(ステップS23)。例えば、第2の生成部37は、MachineCodeEmitter関数を呼び出すコード「MaschineCodeEmitter(nm,oplist);」を生成し、それをニーモニック関数の内部に記述する。このとき、第2の生成部37は、MaschineCodeEmitterの第2引数に、ステップS22の型変換後の配列「oplist」を渡す。これと共に、第2の生成部37は、図20のコードT11、T12等のような変数の宣言と代入を行う文もソースファイル34に記述する。
続いて、第3の生成部38が、MachineCodeEmitter関数が生成した機械語をメモリ3に書き込むコードを生成し、それをソースファイル34に記述する(ステップS24)。一例として、第3の生成部38は、関数writeの引数にMachineCodeEmitter関数を記述した「write(MachineCodeEmitter(nm, oplist));」というコードをソースファイル34に記述する。
そして、命令情報33に含まれる全ての行に対してステップS20~S24の処理を行う。その後、出力部39が、全てのニーモニック関数を含むソースファイル34を記憶部32に書き出す(ステップS25)。
以上説明した本実施形態によれば、ステップS21において、第1の生成部36が、ニーモニック関数の引数の型をオペランドの型に宣言するコードT11(図20(a)参照)を生成する。これにより、複数のニーモニック関数の関数名を同一にすることができるため、開発者が覚えるべき関数名が増加するのを防止できる。
しかも、図22(a)、(b)を参照して説明したように、ニーモニック関数の引数の型が間違っているとコンパイル時にエラーが出るため、ソースファイル41のバグを低減できる。そのため、バグのあるプログラムをターゲットマシン1で無駄に実行する時間が減り、ターゲットマシン1のハードウェア資源の無駄な消費を改善でき、かつ開発者がデバックをするのに要する工数を改善できる。
(第3実施形態)
命令セットに含まれる命令には、オペランドの値に制限が課せられている命令がある。例えば、「mov オペランド0、オペランド1」というフォーマットで記述されるmov命令においては、「オペランド1」の即値の範囲は、符号付9ビットの整数で表現できる-256~+255に制限される。開発者がこのような制限を忘れてニーモニック関数movをソースファイル34に記述しても、そのソースファイル34はコンパイル時にエラーとはならず、プログラム実行時にエラーとなる。これについて図24(a)、(b)を参照しながら説明する。
図24(a)は、第2実施形態に従って生成したニーモニック関数movのC++のソースコードが記述されたソースファイル34の例を示す図である。このソースコードにおいては、引数のOP0、OP1に対してはRegister型やImmediate型等の型の制限はあるものの、引数の値自体には制限がない。
図24(b)は、このニーモニック関数movを利用して開発者が記述したアプリケーションプログラム用のソースファイル41のC++の疑似ソースコードの例を示す図である。
この例では、文「imm.value=-1000000;」により、変数immのメンバ「value」に値「-1000000」を代入している。前述のように、mov命令の第2オペランドの値は-256~+255の範囲内に制限されているため、値「-1000000」は第2引数として不適切な値である。
しかし、ソースファイル41はC++の文法上は正しく記述されているためコンパイル時にエラーは発生しない。また、コンパイルで得られた実行可能プログラムを実行すると、その実行可能プログラムは、MachineCodeEmitter関数を呼び出すことにより、即値-1000000をレジスタに格納するmov命令に対応する機械語を生成しようとする。但し、そのような動作に対応する機械語は存在しないので、実行可能プログラムはその機械語を生成することができずエラーを出力する。このとき、ソースファイル41の記述行数が多い場合には、そのソースファイル41におけるどのニーモニック関数の呼び出しがこのエラーの原因となっているかを開発者が特定するのは難しい。
そこで、本実施形態では、以下のようにしてソースファイル41におけるソースコードの誤りを開発者が気付けるようにする。
図25は、本実施形態で使用する命令情報33について模式的に示す図である。
図25に示すように、本実施形態に係る命令情報33においては、関数名、ニーモニック、オペランドの個数、オペランドの型、及びオペランドに課された制限の各々が対応付けられて格納される。第1、第2実施形態と同様に、この命令情報33は、開発者によって予め作成される。
また、第1、第2実施形態と同様に、命令情報33の各々の行はそれぞれ異なる命令に対応する。例えば、1行目はmov命令に対応しており、オペランドに課された制限は{レジスタのインデックスの範囲が0~31、即値の範囲が-256~+255}というリスト形式で表現される。なお、そのリストの第1成分は第1オペランドに対する制限を表し、第2成分は第2オペランドに対する制限を表す。命令が第3オペランドをとる場合には、その第3オペランドに対する制限がリストの第3成分に格納される。
また、命令情報33の2行目はshiftR命令に対応しており、オペランドに課された制限は{レジスタのインデックスの範囲が0~31、レジスタのインデックスの範囲が0~31、即値の範囲が-63~+63}となる。
図26は、mov命令に対応した本実施形態に係るニーモニック関数movが記述されたソースファイル34のC++の疑似ソースコードの例について示す模式図である。
このニーモニック関数movのソースコードは、命令情報33に基づいて制御部31が次のように生成する。
まず、制御部31は、第2実施形態と同様にしてニーモニック関数movにコードT11~T15を記述する。更に、制御部31は、命令情報33を参照することにより、オペランドに課せられた制限を命令ごとに取得する。例えば、mov命令の場合は、{レジスタのインデックスの範囲が0~31、即値の範囲が-256~+255}という制限を制御部31が取得する。
そして、制御部31は、ニーモニック関数movの引数が表すオペランドが上記の制限を違反している場合に例外を発生させるコードT16を生成し、それをソースファイル34に記述する。
ここでは、if文によりオペランドが制限を違反しているかどうかを判断し、違反している場合にthrow文で例外を生成する。例えば、「OP0」のregIndexの値が0~31の範囲にない場合には、プログラム実行の際に「”Invalid register index is passed to mov mnemonic function.”」というエラーメッセージが標準出力に出力される。また、「OP1」のvalueの値が-256~+255の範囲にない場合には、プログラム実行の際に「”Invalid immediate value is passed to mov mnemonic function.”」というエラーメッセージが標準出力に出力される。
そして、図27は、このニーモニック関数movを利用して開発者が記述したアプリケーションプログラム用のソースファイル41のC++の疑似ソースコードの例を示す図である。
この例では、文「imm0.value = 1000000;」により、ニーモニック関数movの第2引数「imm0」のメンバ「value」に1000000を代入している。前述のように、mov命令の第2オペランドの値は-256~+255の範囲に制限されている。よって、文「mov(reg0, imm0);」を実行すると例外が発生し、「”Invalid immediate value is passed to mov mnemonic function.”」という文字列が標準出力に出力されることになる。
これにより、開発者は、ニーモニック関数movの引数がmov命令の制限を違反していることに気づくことができ、ソースコード66を簡単にデバッグすることができる。
[処理の流れ]
次に、本実施形態に係る関数生成方法について説明する。
図28は、本実施形態に係る関数生成方法について示すフローチャートである。
まず、第1の生成部36が、命令情報33を参照して、相互に対応する関数名、ニーモニック、オペランドの個数、オペランドの型、及びオペランドに課された制限を取得する(ステップS30)。
次いで、第1の生成部36が、中身が空のニーモニック関数を生成し、それをソースファイル34に記述する(ステップS31)。そのニーモニック関数の引数の個数は、ステップS30で取得部35が取得したオペランドの個数である。また、その引数の型は、ステップS30で取得部35が取得したオペランドの型である。
次に、第2の生成部37が、ニーモニック関数が引数として受け取った変数に対応するオペランドが制限を違反している場合に例外を発生させるコードを生成する(ステップS32)。例えば、第2の生成部37は、図26で説明したコードT16を生成し、それをニーモニック関数の内部に記述する。
次に、第2の生成部37が、ニーモニック関数が引数として受け取った変数の型を、MachineCodeEmitter関数の第2引数であるoperand型の配列に変換するコードを生成する(ステップS33)。例えば、第2の生成部37は、図26で説明したコードT14をニーモニック関数の内部に記述する。
次いで、第2の生成部37がMachineCodeEmitter関数を呼び出すコードを生成する(ステップS34)。例えば、第2の生成部37は、ニーモニック関数の内部に「MaschineCodeEmitter(nm,oplist)」というコードを記述する。これと共に、第2の生成部37は、図26のコードT12、T13等のような変数の宣言と代入を行う文もソースファイル34に記述する。
続いて、第3の生成部38が、MachineCodeEmitter関数が生成した機械語をメモリ3に書き込むコードを生成する(ステップS35)。例えば、第3の生成部38は、関数writeの引数にMachineCodeEmitter関数を記述した「write(MachineCodeEmitter(nm, oplist));」というコードをソースファイル34に記述する。
そして、命令情報33に含まれる全ての行に対してステップS30~S35の処理を行う。その後、出力部39が、全てのニーモニック関数を含むソースファイル34を記憶部32に書き出す(ステップS36)。
以上説明した本実施形態によれば、ステップS32において、第2の生成部37が、オペランドが制限を違反している場合に例外を発生させるコードT16(図26参照)を生成する。そのため、開発者が早期にソースコード66(図27参照)の誤りに気付くことができ、開発者がデバッグするのに要する工数を減らすことができる。しかも、バグのあるプログラムをターゲットマシン1で無駄に実行する時間が減り、ターゲットマシン1のハードウェア資源の無駄な消費を改善できる。
なお、命令情報33の「オペランドに課された制限」の種類としては、(1)「レジスタインデックスが特定の範囲内である」、(2)「即値が特定の範囲内である」、(3)「即値は整数である」、(4)「即値は小数である」等がある。この場合、制御部31が取得する命令情報33のデータ形式は、「オペランドに課された制限」の種類の番号(1)~(4)と、制限の上限値と、制限の下限値とを有する形式となる。
そして、(1)~(4)に対応するオペランドの違反をチェックするコードのテンプレートをあらかじめ用意しておき、ステップS32では制御部31が必要なテンプレートを参照すればよい。更に、制限の上限値と下限値とをチェックする必要があるケースでは、制御部31がこれらの値をテンプレートに埋め込むことで例外を発生するコードを生成すればよい。
(第4実施形態)
本実施形態では、開発者がソースコードの誤りに気付くのを第3実施形態よりも容易にする。なお、本実施形態で使用するニーモニック関数は特に限定されないが、以下ではadd命令に対応したニーモニック関数を例にして説明をする。そこで、まずadd命令について説明する。
図29(a)、(b)は、add命令のアセンブリの文法について示す図である。
add命令には様々なオペランドをとる種類があるが、図29(a)では「DSTレジスタ」と二つの「SRCレジスタ」とをオペランドとするadd命令について例示している。このadd命令は、二つの「SRCレジスタ」の内容同士を加算した値を「DSTレジスタ」に格納する命令である。
一方、図29(b)は、「DSTレジスタ」、「SRCレジスタ」、及び「即値」の三つのオペランドをとるadd命令を例示する図である。このadd命令は、「SRCレジスタ」の内容に「即値」を加算した値を「DSTレジスタ」に格納する命令である。
図30は、本実施形態に係る命令情報33を模式的に示す図である。
図30に示すように、この命令情報33には、第3実施形態に従って関数名、ニーモニック、オペランドの個数、オペランドの型、及びオペランドに課された制限の各々が対応付けられて格納される。なお、本実施形態では関数名をアルファベットの大文字で表すことにする。また、第1~第3実施形態と同様に、命令情報33は開発者によって予め作成される。
図29(a)、(b)の二つのadd命令に対応して命令情報33には二つの関数名「ADD」が格納されているため、制御部31は、第3実施形態に従って二つのニーモニック関数ADDを生成することになる。第3実施形態で説明したように、引数の個数と関数名とが同一の複数のニーモニック関数が存在しても、それらの引数の型が異なればC++の文法上は両者を区別することができる。
以下では、命令情報33の二行目に対応したニーモニック関数ADDを例にして説明する。命令情報33によれば、このニーモニック関数ADDのオペランドの型は{Register型,Register型,Immediate型}である。また、第1オペランドと第2オペランドに課された制限は、いずれも「レジスタのインデックスの範囲が0~31」である。そして、第3オペランドに課された制限は、「即値の範囲が-1024~+1023」である。
図31は、この命令情報33に基づいて、第3実施形態に従って制御部31が生成したニーモニック関数ADDのソースコードの一例を示す図である。
ここでは、ファイル名が「mnemonic.h」のソースファイル34を制御部31が生成し、そのソースファイル34の20行目からニーモニック関数ADDの記述が始まるものとする。なお、このソースファイル34において第3実施形態で説明したのと同種のコードには第3実施形態と同じ符号を付し、その説明は省略する。
図31に示すように、このソースファイル34には、第3実施形態で説明したコードT11~T16が制御部31によって生成される。このうち、コードT16は、ニーモニック関数ADDの引数が表すオペランドが命令情報33における制限を違反している場合に例外を発生させるコードである。
更に、この例では、ソースファイル34の21行目に、制御部31が関数「SET()」を呼び出すコードT17を生成する。
図32は、関数「SET()」を定義するC++の疑似ソースコードを模式的に示す図である。
関数「SET()」の定義は、制御部31によってソースファイル34であるmnemonic.hの一部に記述される。この例では、制御部31が、関数「SET()」を定義するためのコードT20~T22をソースファイル34に生成する。
このうち、コードT20は、関数「SET()」のマクロを宣言するコードである。ここでは、関数「SET()」は、プリプロセッサによって関数「setCodeInfo(__FILE__, __LINE__, __func__)」に置換されるものとして定義される。
その関数「setCodeInfo」の引数に現れる変数「__FILE__」と「__LINE__」はC++における事前定義マクロであり、変数「__func__」はC++における事前定義識別子である。これらの変数は、コンパイル時にプリプロセッサによって所定の内容に変換される。例えば、「__FILE__」は、当該「__FILE__」が記述されたファイルのファイル名に変換される。また、「__LINE__」は、当該「__LINE__」が記述された行番号に変換される。そして、「__func__」は、当該「__func__」が記述された関数の関数名に変換される。
一方、コードT21は、char型のグローバル変数「g_filename」、「g_funcname」とint型のグローバル変数「g_line」とを定義するコードである。
そして、コードT22は、関数「setCodeInfo」の中身を定義するコードである。関数「setCodeInfo」は、三つの引数「filename」、「line」、及び「funcname」を受け取り、その各々をグローバル変数「g_filename」、「g_line」、及び「g_funcname」に代入する関数として定義される。
この例では、ソースファイル34(図31参照)のコードT17の位置においてプリプロセッサが「SET()」を「setCodeInfo(__FILE__, __LINE__, __func__)」に置換する。更に、プリプロセッサは、「__FILE__」を呼び出し元のソースファイル34のファイル名である文字列「mnemonic.h」に置換し、「__LINE__」をソースファイル34における関数「SET()」の行番号である「21」に置換する。また、プリプロセッサは、「__func__」を関数「SET()」の呼び出し元の関数であるニーモニック関数ADDの関数名「ADD」に置換する。
よって、ソースファイル34をコンパイルして生成した実行可能プログラムを実行すると、コードT17に対応する部分の実行時に、変数「g_filename」に「mnemonic.h」が格納され、変数「g_funcname」に「ADD」が格納される。そして、変数「g_line」に「21」が格納される。
図33は、開発者がC++で記述したアプリケーションプログラム用のソースファイル41の疑似ソースコードを模式的に示す図である。ここではソースファイル41のファイル名を「sample.cpp」とし、開発者がそのソースファイル41にコードT25~T28を記述したものとする。
このうち、コードT25は、「reg0」、「reg1」、及び「imm0」の各変数を定義する文である。このうち、変数「reg0」及び「reg1」はReg型として定義される。また、変数「imm0」はImm型として定義される。
また、コードT26は、「reg0」、「reg1」、及び「imm0」の各変数のメンバに値を代入する文である。この例では、変数「reg0」のメンバ「regIndex」に「0」が代入され、変数「reg1」のメンバ「regIndex」に「1」が代入される。そして、変数「imm0」のメンバ「value」には「100000」が代入される。
一方、コードT27は、ニーモニック関数ADDを呼び出すと共に、その引数に上記の各変数「reg0」、「reg1」、「imm0」の内容を渡すコードである。ここでは、例外処理を行うために開発者がtry文の内部にコードT27を記述する。前述のように変数「imm0」には値「100000」が代入されているが、命令情報33(図30参照)によればニーモニック関数addの第3引数がとり得る値は-1024~+1023の範囲に制限されている。よって、このニーモニック関数ADDを実行するとコードT16(図31参照)において例外が投げられることになる。
そして、コードT28は、このように例外が投げられたときに、各グローバル変数「g_filename」、「g_line」、及び「g_filename」の内容を標準出力に出力するためのコードである。この例では前述のように「g_filename」、「g_line」、及び「g_filename」の各々に「mnemonic.h」、「22」、及び「ADD」が格納されているため、これらが標準出力に出力されることになる。
このソースファイル41から実行可能プログラム44(図13参照)を生成するには、第1実施形態で説明した図13の処理に従ってプログラム群42がビルドを行えばよい。
図34は、このようにして生成した実行可能プログラム44をターゲットマシン1(図1参照)で実行したときの標準出力への出力例を示す図である。
この例では、前述のようにソースファイル41(図33参照)におけるニーモニック関数ADDの第3引数が命令情報33で規定される制限を満たしていない。よって、標準出力には、コードT16(図31参照)における「Invalid immediate value of OP2 is passed to add mnemonic function.」というエラーメッセージ74が出力される。更に、コードT28(図33参照)における各グローバル変数「g_filename」、「g_line」、及び「g_funcname」の内容を示すメッセージ75も標準出力に出力される。
開発者は、エラーメッセージ74とメッセージ75とに基づいて、自らが記述したプログラムのどこかでニーモニック関数ADDの引数を誤って指定していることに気づくことができる。
しかし、メッセージ75には、誤りのあるソースファイル41のファイル名である「sample.cpp」ではなく、ニーモニック関数ADDを定義しているソースファイル34のファイル名「mnemonic.h」が出力されている。更に、メッセージ75における行数や関数名にも、記述に誤りがあるソースファイル41(sample.cpp)における行数や関数名ではなく、ソースファイル34(mnemonic.h)の行数や関数名が出力される。
これではアプリケーションプログラム用のソースファイル41(sample.cpp)のどこに間違いがあるのか開発者が分らず、アプリケーションプログラムのデバッグに長時間を要し、プログラム開発が非効率となってしまう。更に、コンパイラに対し複数のソースファイル41を与えている場合、どのソースファイル41の中のADD関数の使用で誤っているのかの判別も困難である。
この点に鑑み、本実施形態では以下のようにして開発者がデバッグするのを容易にする。
[機能構成]
図35は、本実施形態に係る情報処理装置30の機能構成図である。
なお、図35において、第1~第3実施形態で説明したのと同じ要素にはこれらの実施形態におけるのと同じ符号を付し、以下ではその説明を省略する。
図35に示すように、情報処理装置30の制御部31は、既述の第1~第3の生成部36~38と出力部39の他に、第4の生成部80と定義ファイル生成部81とを有する。
図36は、本実施形態において制御部31が生成したニーモニック関数ADDのC++の疑似ソースコードを示す模式図である。ここでは、ファイル名が「mnemonic.h」というソースファイル34を制御部31が生成し、そのソースファイル34に制御部31がニーモニック関数ADDを生成するものとする。
なお、図36において、第1~第3実施形態で説明したのと同種のコードには同じ符号を付し、以下ではその説明を省略する。
図36に示すように、本実施形態では、第1実施形態と同様にして第1の生成部36がニーモニック関数ADDの引数にコードT11を生成する。そのコードT11は、命令addの三つのオペランドに対応した各引数「OP0」、「OP1」、及び「OP2」の型を宣言するコードである。
また、第1の生成部36は、ニーモニック関数ADDの複数の引数のうちの最初の位置にコードT18を記述する。コードT18は、「strFile」、「line」、及び「strFunc」の各変数の型を定義するコードである。これらの変数のうち、「strFile」は、ファイル名を格納するための文字列型の変数である。また、「line」は、ファイルにおける行数を格納するための整数型の変数である。そして、「strFunc」は、関数名を格納するための文字列型の変数である。なお、コードT18における「strFile」、「line」、及び「strFunc」の各変数を記述する順序は特に限定されない。第1の生成部36は、これらの変数を任意の順序でコードT18に記述し得る。
そして、制御部31は、第3実施形態と同様にしてその他のコードT12~T16をソースファイル34に生成する。
更に、これらのコードT12~T16の他に、第4の生成部80がソースファイル34にコードT17を生成する。図31の例と同様に、コードT17は、関数「SET()」を呼び出すコードである。また、第4の生成部80は、ソースファイル34の一部に関数「SET()」の処理を定義するコードを生成する。
図37は、本実施形態において第4の生成部80が生成する関数「SET()」のC++の疑似ソースコードの一例を示す図である。
図32の例と異なり、本実施形態では、コードT20において関数「setCodeInfo」の引数に、ニーモニック関数ADDの引数である「strFile」、「line」、及び「strFunc」の各変数が渡される。
また、コードT21とT22の各々は、図32の例と同様に関数「setCodeIndo」の各引数をグローバル変数「g_filename」、「g_funcname」、及び「g_line」の各々に代入するコードである。
一方、定義ファイル生成部81(図35)は、図38に例示する定義ファイル82を生成する処理部である。
図38は、定義ファイル生成部81が生成した定義ファイル82の疑似ソースコードを示す模式図である。
図38に示すように、定義ファイル82は、「#define」で始まる複数のマクロを有する。これらのマクロは、ニーモニック関数の各々に対応するように定義ファイル生成部81により生成される。そして、各マクロは、開発者が記述したアプリケーションプログラム用のソースファイルにおける各ニーモニック関数の引数に新たな変数を追加する指示をプリプロセッサに与えるマクロとなっている。これについて図39のソースファイルを例にして説明する。
図39は、本実施形態において開発者が記述したアプリケーションプログラム用のソースファイル41のC++の疑似コードを示す図である。なお、図39において、図33で説明したのと同じコードには図33におけるのと同じ符号を付し、以下ではその説明を省略する。
なお、このソースファイル41においては、図33の例とは異なり、開発者がニーモニック関数の関数名をアルファベットの小文字で記述するものとする。例えば、開発者は、101行目においてニーモニック関数を呼び出すコードT27を「add(reg0, reg1, imm0)」と記述する。そのコードT27におけるニーモニック関数addの第3引数「imm0」のメンバ「value」には、コードT26によって「100000」という値が代入されている。この値は、命令情報33(図30参照)における「-1024~1023」との制限を満たさない不適切な値である。
この場合の定義ファイル82(図38参照)の一行目のマクロ「#define add(...) ADD(__FILE__, __LINE__, __func__, __VA_ARGS__)」の動作について説明する。
まず、このマクロは、ソースファイル41におけるニーモニック関数addの関数名「add」を「ADD」に置換するようにプリプロセッサに指示を出す。更に、このマクロは、ニーモニック関数addの引数の前に、新たな引数として「__FILE__」、「__LINE__」、及び「__func__」の各々を追加するようにプリプロセッサに指示を出す。なお、「__VA_ARGS__」は、ニーモニック関数addの引数が格納される可変長引数を示す事前定義識別子である。これにより、ソースファイル41の101行目の記述「add(reg0, reg1, imm0);」は、プリプロセッサによって「ADD(__FILE__, __LINE__, __func__, reg0, reg1, imm0);」と置換されることになる。
前述のように、「__FILE__」、「__LINE__」、及び「__func__」の各々は、ファイル名、行番号、及び関数名に置換されるC++の事前定義マクロや事前定義識別子である。プリプロセッサは、これらの事前定義マクロや事前定義識別子の各々を、ファイル名、行番号、及び関数名に置換する。なお、ファイル名、及び行番号の各々は、ニーモニック関数addに関する関数情報の一例である。したがって、ニーモニック関数「ADD」の引数として、ニーモニック関数「add」が記述されたファイル名、行番号、関数名が渡されることになる。
定義ファイル生成部81は、命令情報33(図30参照)を参照することによりこのような定義ファイル82を生成し、それを記憶部32に格納する。
例えば、定義ファイル生成部81は、命令情報33を一行ずつ読み込んで関数名を取得し、その関数名ごとにディレクティブを生成する。取得した関数名がSUBの場合には、定義ファイル生成部81は、定義ファイル82にディレクティブ「#define sub(...) SUB(__FILE__, __LINE__, __func__, __VA_ARGS__)」を生成することになる。
[開発環境]
図40は、本実施形態に係る開発環境について示す模式図である。
なお、図40において、第1実施形態の図13で説明したのと同じ要素には第1実施形態におけるのと同じ符号を付し、以下ではその説明を省略する。
ここでは、情報処理装置30の内部に開発環境を構築する場合を想定する。その場合、制御部31がニーモニック関数のソースファイル34と定義ファイル82とを生成する。
一方、開発者は、C++を用いてアプリケーションプログラム用のソースファイル41を作成する。以下では、開発者が図39のようにファイル名が「sample.cpp」のソースファイル41を作成し、そのソースファイル41の101行目にニーモニック関数andを呼び出すコードT27を記述した場合について説明する。
そして、開発者の指示の下で、コンパイラ、アセンブラ、及びリンカのプログラム群42がビルドを行う。ビルドに際しては、まずコンパイラに含まれるプリプロセッサがソースファイル34、41、43と定義ファイル82とを読み込む。なお、第1実施形態で説明したように、MachineCodeEmitter関数が記述されたソースファイル43に代えて、機械語生成関数が記述されたバイナリ形式の実行ライブラリファイル43aを使用してもよい。
次いで、プリプロセッサが、定義ファイル82に従って、ソースファイル41の101行目の「add(reg0, reg1, imm0);」を「ADD(__FILE__, __LINE__, __func__, reg0, reg1, imm0);」に置換する。
このとき、プリプロセッサは、更に「__FILE__」、「__LINE__」、及び「__func__」の各々に、ソースファイル41の101行目を実行した時点での内容を格納する。よって、「__FILE__」にはソースファイル41のファイル名である「sample.cpp」が格納される。また、「__LINE__」には、ソースファイル41においてニーモニック関数addが記述されている行番号の「101」が格納される。更に、「__func__」には、プリプロセッサによって置換された後の関数名である「func0」が格納される。
そして、「sample.cpp」、「101」、及び「func0」の各々の内容は、ソースファイル34におけるニーモニック関数ADD(図36参照)に、引数「strFile」、「line」、及び「strFunc」として渡される。この状態で当該ソースファイル34のコードT17における関数「SET()」が実行されることにより、グローバル変数「g_filename」、「g_funcname」、及び「g_line」の各々への代入が実行される。これにより、本実施形態では、グローバル変数「g_filename」、「g_funcname」、及び「g_line」の各々に「sample.cpp」、「func0」、及び「101」が代入されることになる。
続いて、コンパイラがアセンブリファイルを生成し、更にアセンブラがそのアセンブリファイルを機械語の命令列に変換してオブジェクトファイルを生成する。
その後、リンカは、オブジェクトファイルと種々のライブラリとをリンクすることにより、プロセッサ2(図1参照)で実行可能なバイナリ形式の実行可能プログラム44を生成する。
図41は、このようにして生成した実行可能プログラム44をターゲットマシン1(図1参照)で実行したときの標準出力への出力例を示す図である。
前述のように、この例ではソースファイル41におけるニーモニック関数ADDの第3引数が命令情報33で規定される制限を満たしていない。よって、標準出力には、コードT16(図36参照)における「Invalid immediate value of OP2 is passed to add mnemonic function.」というエラーメッセージ84が出力される。
更に、図39のコードT28における各グローバル変数「g_filename」、「g_line」、及び「g_funcname」の内容を示すメッセージ85も標準出力に出力される。
このとき、本実施形態では、定義ファイル82(図38参照)を使用したことで、前述のようにグローバル変数「g_filename」、「g_funcname」、及び「g_line」の各々内容は「sample.cpp」、「func0」、及び「101」となっている。
よって、ソースファイル41(図39参照)のコードT28を実行することにより、これらの内容を含む「file name:sample.cpp, line:101, function name: func0」というメッセージ85が標準出力に出力される。そのメッセージ85には、開発者が自ら記述したアプリケーションプログラム用のソースファイル41のファイル名「sample.cpp」と、そのソースファイル41でエラーが発生した行数「101」と、エラーが発生した関数名「func0」が含まれる。
よって、図34の例と異なり、本実施形態では、エラーが発生したソースファイル41のファイル名や、そのソースファイル41でエラーが発生した位置を開発者が特定することができ、開発者が容易にデバッグをすることができる。その結果、デバッグに要する時間を短縮でき、プログラム開発を効率化することが可能となる。
なお、図41におけるのと同様の実行結果を得るために、定義ファイル82を使用せずに、例えば開発者が図42に示すアプリケーション用のソースファイル41を記述することも考えられる。
図42は、本実施形態の別の例に係るソースファイル41のC++の疑似ソースコードの例を示す模式図である。
図42の例では、開発者が、ソースファイル41にニーモニック関数ADDを記述すると共に、その引数に「__FILE__」、「__LINE__」、及び「__func__」の各事前定義マクロや事前定義識別子を自ら記述する。この場合は、ニーモニック関数ADDが記述されたソースファイル41のファイル名が「__FILE__」に格納される。また、ソースファイル41においてニーモニック関数ADDが記述されている行番号と、その記述を含む関数func0の関数名がそれぞれ「__LINE__」と「__func__」に格納される。
このような記述を行うことによっても図41におけるのと同様の実行結果を得ることができる。しかし、関数の引数に「__FILE__」、「__LINE__」、及び「__func__」の各事前定義マクロと事前定義識別子を開発者が自ら記述するのは極めて煩わしく、更にタイプミスも発生する恐れもある。
これに対し、本実施形態では定義ファイル生成部81が自動的に定義ファイル82を生成するため、このような煩雑さを回避することができ、開発者の負担減を図ることができる。
なお、本実施形態では、図36に示したように、ソースファイル34においてニーモニック関数ADDの引数を示すコードT18をコードT11の前の位置に記述したが、順番を逆にしてコードT18をコードT11の後ろの位置に記述することも考えられる。この場合は、ニーモニック関数ADDに対応したマクロも、引数の順番を逆にして「#define add(...) ADD(__VA_ARGS__, __FILE__, __LINE__, __func__)」となる。しかし、このような記述では以下のような不都合が生じる。
図43(a)、(b)は、そのような不都合について模式的に示す図である。
命令セットに含まれる命令には、同一のニーモニックでオペランドの個数が異なる命令が存在する。ここで、add命令がそのような命令の一つであり、レジスタ型のオペランドを3個とるadd命令と、3個のレジスタ型と1個の即値型の合計4個のオペランドをとるadd命令が存在する場合を説明する。
レジスタ型のオペランドを3個とるadd命令は、第2、第3オペランドで指定されるレジスタの値を加算し、その結果を第1オペランドで指定されるレジスタに格納する命令とする。
一方、3個のレジスタ型と1個の即値型の合計4個のオペランドをとるadd命令は、第2、第3オペランドで指定されるレジスタの値を加算する命令とする。その加算の結果は、第3オペランドで指定される即値と加算され、その結果は第1オペランドに格納される。
この場合、前者のadd命令は、後者のadd命令の即値を「0」としたケースとして考えることができる。
一方、C++では、関数の定義において複数の引数を記述した場合であっても、省略時の値が明記された最後の引数を省略してその関数を呼び出すことができる。この特徴を利用して、本実施形態においては、オペランドの個数が異なる2種類のadd命令に対応した一つのニーモニック関数addの定義のみをソースファイル34に記述する。
図43(a)、(b)における「void ADD(Reg x1, Reg x2, Reg x3, Imm imm=imm(0), string &strFile, size_t line, string &strFunc」が、このように2種類のadd命令の各々の引数を考慮したニーモニック関数ADDであったとする。
このニーモニック関数ADDにおいては、最初の四個の引数「x1」、「x2」、「x3」、「imm」がadd命令のオペランドに対応する。なお、前述のように、この例ではコードT11、T18の順序が図36の例と逆になっている。
この場合に、コンパイルが成功する図43(a)についてまず説明する。
図43(a)の例では、アプリケーションプログラム用のソースファイル41に開発者がコード「add(x1, x2, x3, imm)」を記述した場合を想定している。そのコード「add(x1, x2, x3, imm)」は、4個のオペランドをとるadd命令に対応したコードである。
この場合、定義ファイル82におけるマクロ「#define add(...) ADD(__VA_ARGS__, __FILE__, __LINE__, __func__)」によって、プリプロセッサは上記のコードを「ADD(x1, x2, x3, imm, __FILE__, __LINE__, __func__)」に置換する。
そして、置換後のこのコードが、ソースファイル34における関数ADDの定義を呼び出す。この場合、「ADD(x1, x2, x3, imm, __FILE__, __LINE__, __func__)」とソースファイル34における関数ADDの7個の引数の各々の型は一致する。よって、コンパイルは成功することになる。
一方、図43(b)はコンパイルが失敗する場合を例示する模式図である。
ここでは、開発者が、3個のオペランドをとるadd命令に対応した3個の引数を含むコード「add(x1, x2, x3)」をソースファイル41に記述した場合を想定している。この場合は、定義ファイル82におけるマクロ「#define add(...) ADD(__VA_ARGS__, __FILE__, __LINE__, __func__)」によって、プリプロセッサは上記のコードを「ADD(x1, x2, x3, __FILE__, __LINE__, __func__)」に置換する。そして、置換後のこのコードが、ソースファイル34における関数ADDの定義を呼び出す。
しかし、「ADD(x1, x2, x3, __FILE__, __LINE__, __func__)」の第6引数「__func__」は文字列型であるのに対し、ソースファイル34における関数ADDの第6引数「line」は整数型である。よって、呼び出し側と呼び出される側の各々の引数の型が一致せず、コンパイルは成功しない。
このような不都合を回避するために、図36に示したように、第1の生成部36が、ニーモニック関数ADDの複数の引数のうちの最初の位置に、ファイル名等の関数情報を記述したコードT18を記述するのが好ましい。
例えば、図43(a)のソースファイル34においてコードT11、T18の順番を入れ替え、本実施形態のようにコードT11よりも前の位置にコードT18を記述し、かつソースファイル41に「add(x1, x2, x3)」と記述した場合を考える。この場合は、定義ファイル82のマクロ「#define add(..) ADD(__FILE__, __LINE__, __func__, __VA_ARGS__)」により、プリプロセッサが上記のコードを「ADD(__FILE__, __LINE__, __func__, x1, x2, x3)」に置換する。コンパイラは、このように6個の引数を持つADD関数の呼び出しを、ソースファイル34における7個の引数を持つ関数ADDの定義において7個目の引数を省略した呼び出しであることをC++の文法に即して認識できる。
また、省略されていない6個の引数はそれぞれ、文字列型、整数型、文字列型、レジスタ型、レジスタ型、レジスタ型であり、これはソースファイル34で定義されているADD関数の最初の6個の引数の型に一致している。よって、上記の記述「add(x1, x2, x3)」は、エラーなくコンパイルすることができる。
[処理の流れ]
次に、本実施形態に係る定義ファイルの生成方法について説明する。
図44は、本実施形態に係る定義ファイルの生成方法について示すフローチャートである。
まず、定義ファイル生成部81が、命令情報33(図30参照)から関数名を取得し(ステップS40)、その関数名に対応したマクロ#defineを生成する(ステップS41)。例えば、定義ファイル生成部81が命令情報33の1行目の関数名「ADD」を取得した場合を考える。この場合は、定義ファイル生成部81は、「#define add(...) ADD(__FILE__, __LINE__, __func__, __VA_ARGS__)」というマクロを生成する。
そして、定義ファイル生成部81は、命令情報33(図30参照)の各行に対してステップS40とステップS41とを繰り返す。なお、上記のマクロ「#define add(...) ADD(__FILE__, __LINE__, __func__, __VA_ARGS__)」は、置換前の関数名「add」と置換後の関数名「ADD」を除き、全ての関数名について同じ書式である。よって、関数名が同一の場合にはマクロも同一となるため、関数名が重複している場合には、定義ファイル生成部81は、命令情報33の次の関数名からステップS40とステップS41とを繰り返す。
その後、定義ファイル生成部81が、命令情報33における全ての関数名に対応したマクロが記述された定義ファイル82を記憶部32に書き出す(ステップS42)。
以上により、本実施形態に係る定義ファイルの生成方法の基本ステップを終了する。
(ハードウェア構成)
次に、第1~第4実施形態に係る情報処理装置30のハードウェア構成について説明する。
図45は、第1~第4実施形態に係る情報処理装置30のハードウェア構成図である。
図45に示すように、情報処理装置30は、記憶装置30a、メモリ30b、プロセッサ30c、通信インターフェース30d、表示装置30e、及び入力装置30fを有する。これらの各部は、バス30gにより相互に接続される。
このうち、記憶装置30aは、HDDやSSD(Solid State Drive)等の不揮発性のストレージデバイスであり、本実施形態に係る関数生成プログラム90を記憶する。
なお、関数生成プログラム90をコンピュータが読み取り可能な記録媒体30hに記録させておき、プロセッサ30cに記録媒体30hの関数生成プログラム90を読み取らせるようにしてもよい。
そのような記録媒体30hとしては、例えばCD-ROM(Compact Disc - Read Only Memory)、DVD(Digital Versatile Disc)、及びUSB(Universal Serial Bus)メモリ等の物理的な可搬型記録媒体がある。また、フラッシュメモリ等の半導体メモリやハードディスクドライブを記録媒体30hとして使用してもよい。これらの記録媒体30hは、物理的な形態を持たない搬送波のような一時的な媒体ではない。
更に、公衆回線、インターネット、及びLAN(Local Area Network)等に接続された装置に関数生成プログラム90を記憶させておき、プロセッサ30cがその関数生成プログラム90を読み出して実行するようにしてもよい。
一方、メモリ30bは、DRAM等のようにデータを一時的に記憶するハードウェアであって、その上に前述の関数生成プログラム90が展開される。
プロセッサ30cは、情報処理装置30の各部を制御したり、メモリ30bと協働して関数生成プログラム90を実行したりするCPU(Central Processing Unit)やGPU(Graphical Processing Unit)等のハードウェアである。
このようにメモリ30bとプロセッサ30cとが協働して関数生成プログラム90を実行することにより、図11の第1の生成部36、第2の生成部37、第3の生成部38、及び出力部39を備えた制御部31が実現される。また、図35の第4の生成部80と定義ファイル生成部81も、メモリ30bとプロセッサ30cとが協働して関数生成プログラム90を実行することにより実現される。また、図11と図35の各々の記憶部32は、記憶装置30aとメモリ30bによって実現される。
更に、通信インターフェース30dは、情報処理装置30をLAN等のネットワークに接続するためのインターフェースである。
そして、表示装置30eは、液晶表示装置等のハードウェアであって、開発者に種々の情報の入力を促すプロンプトや、コンパイル時のエラーメッセージ等を表示する。また、入力装置30fは、キーボードやマウス等のハードウェアである。例えば、開発者は、入力装置30fを操作することにより、情報処理装置30に対してコンパイルの実行の指示を出すことになる。
1…ターゲットマシン、2…プロセッサ、3…メモリ、4…計算コア、5…レジスタファイル、30…情報処理装置、30a…記憶装置、30b…メモリ、30c…プロセッサ、30d…通信インターフェース、30e…表示装置、30f…入力装置、30g…バス、30h…記録媒体、31…制御部、32…記憶部、33…命令情報、34…ニーモニック関数のソースファイル、36…第1の生成部、37…第2の生成部、38…第3の生成部、39…出力部、80…第4の生成部、81…定義ファイル生成部。

Claims (12)

  1. 命令に関する命令情報を記憶した記憶部を参照して、前記命令に対応した関数であって、前記命令のオペランドを表す引数を受け取る第1の関数を生成する処理と、
    前記引数が表す前記オペランドに対して前記命令が行う処理を表す機械語を返す第2の関数を呼び出すコードを前記第1の関数の内部に生成する処理と、
    前記機械語をメモリに書き込むコードを前記第1の関数の内部に生成する処理と、
    をコンピュータに実行させるための関数生成プログラム。
  2. 前記命令情報は、前記オペランドの個数と前記命令の名前とを対応付けた情報であり、
    前記記憶部を参照して、前記命令の名前と同じ関数名を前記第1の関数に付ける処理と、
    前記記憶部を参照して、前記個数に等しい個数の前記引数を宣言するコードを生成する処理とを更に有することを特徴とする請求項1に記載の関数生成プログラム。
  3. 前記命令情報は、前記オペランドの種類を表す型と前記命令とを対応付けた情報であり、
    前記記憶部を参照して、前記引数の型を前記オペランドの前記型に宣言するコードを生成する処理と、
    前記第1の関数が前記引数として受け取った変数を、前記第2の関数の引数の型に変換して該第2の関数に渡すコードを生成する処理とを更に有することを特徴とする請求項1に記載の関数生成プログラム。
  4. 前記命令情報は、前記オペランドの種類を表す型、前記命令、及び前記第1の関数の関数名を対応付けた情報であり、
    前記命令情報に、前記関数名が同一であり、かつ、前記オペランドの型が異なる複数の相異なる前記命令が存在することを特徴とする請求項3に記載の関数生成プログラム。
  5. 前記命令情報は、前記オペランドに課された制限を前記命令に対応付けた情報であり、
    前記記憶部を参照して、前記引数に対応する前記オペランドが前記制限を違反している場合に例外を発生させるコードを生成する処理を更に有することを特徴とする請求項1に記載の関数生成プログラム。
  6. 前記第1の関数を呼び出すようにソースファイルに記述されたコードに引数を追加して、追加した前記引数に、前記ソースファイルにおける前記第1の関数に関する関数情報を格納する指示をプリプロセッサに与える定義ファイルを生成する処理を更に有することを特徴とする請求項5に記載の関数生成プログラム。
  7. 前記命令情報は、前記命令、前記制限、及び前記第1の関数の関数名の各々を対応付けた情報であり、
    前記定義ファイルを生成する処理は、前記命令情報を記憶した前記記憶部を参照して、前記指示を行うマクロを前記関数名ごとに生成することにより行われることを特徴とする請求項6に記載の関数生成プログラム。
  8. 前記関数情報が格納される前記引数を、前記第1の関数の複数の引数のうちの最初の位置に生成する処理を更に有することを特徴とする請求項7に記載の関数生成プログラム。
  9. 前記関数情報は、前記ソースファイルのファイル名、前記ソースファイルにおいて前記第1の関数を呼び出す前記コードが記述された行番号、及び前記第1の関数の関数名のいずれかであることを特徴とする請求項6に記載の関数生成プログラム。
  10. 前記第1の関数を生成する処理において、マクロとして前記第1の関数を生成することを特徴とする請求項1に記載の関数生成プログラム。
  11. 命令に関する命令情報を記憶した記憶部を参照して、前記命令に対応した関数であって、前記命令のオペランドを表す引数を受け取る第1の関数を生成する処理と、
    前記引数が表す前記オペランドに対して前記命令が行う処理を表す機械語を返す第2の関数を呼び出すコードを前記第1の関数の内部に生成する処理と、
    前記機械語をメモリに書き込むコードを前記第1の関数の内部に生成する処理と、
    をコンピュータが実行することを特徴とする関数生成方法。
  12. 命令に関する命令情報を記憶した記憶部を参照して、前記命令に対応した関数であって、前記命令のオペランドを表す引数を受け取る第1の関数を生成する第1の生成部と、
    前記引数が表す前記オペランドに対して前記命令が行う処理を表す機械語を返す第2の関数を呼び出すコードを前記第1の関数の内部に生成する第2の生成部と、
    前記機械語をメモリに書き込むコードを前記第1の関数の内部に生成する第3の生成部と、
    を有することを特徴とする情報処理装置。
JP2021569633A 2020-01-07 2020-01-07 関数生成プログラム、関数生成方法、及び情報処理装置 Active JP7295469B2 (ja)

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
PCT/JP2020/000184 WO2021140568A1 (ja) 2020-01-07 2020-01-07 関数生成プログラム、関数生成方法、及び情報処理装置

Publications (2)

Publication Number Publication Date
JPWO2021140568A1 JPWO2021140568A1 (ja) 2021-07-15
JP7295469B2 true JP7295469B2 (ja) 2023-06-21

Family

ID=76788762

Family Applications (1)

Application Number Title Priority Date Filing Date
JP2021569633A Active JP7295469B2 (ja) 2020-01-07 2020-01-07 関数生成プログラム、関数生成方法、及び情報処理装置

Country Status (3)

Country Link
US (1) US11886839B2 (ja)
JP (1) JP7295469B2 (ja)
WO (1) WO2021140568A1 (ja)

Families Citing this family (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN116302218B (zh) * 2023-03-15 2024-05-10 北京百度网讯科技有限公司 函数信息的添加方法、装置、设备以及存储介质

Family Cites Families (12)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US6247174B1 (en) * 1998-01-02 2001-06-12 Hewlett-Packard Company Optimization of source code with embedded machine instructions
JPH11224199A (ja) 1998-02-06 1999-08-17 Matsushita Electric Ind Co Ltd 翻訳装置と情報処理装置および記録媒体
JP2000056981A (ja) 1998-08-06 2000-02-25 Matsushita Electric Ind Co Ltd プログラム変換装置
JP2001344113A (ja) 2000-05-31 2001-12-14 Nec Corp 実行時コンパイラシステム及び実行時コンパイル方法
US6993754B2 (en) * 2001-11-13 2006-01-31 Hewlett-Packard Development Company, L.P. Annotations to executable images for improved dynamic optimization functions
JP4443100B2 (ja) 2002-07-31 2010-03-31 インターナショナル・ビジネス・マシーンズ・コーポレーション プログラム変換方法、これを用いたデータ処理装置及びプログラム
US7380242B2 (en) * 2003-05-14 2008-05-27 Mainsoft Israel Ltd. Compiler and software product for compiling intermediate language bytecodes into Java bytecodes
US7673293B2 (en) * 2004-04-20 2010-03-02 Hewlett-Packard Development Company, L.P. Method and apparatus for generating code for scheduling the execution of binary code
US7318143B2 (en) * 2004-10-20 2008-01-08 Arm Limited Reuseable configuration data
US8458684B2 (en) 2009-08-19 2013-06-04 International Business Machines Corporation Insertion of operation-and-indicate instructions for optimized SIMD code
KR20120031756A (ko) 2010-09-27 2012-04-04 삼성전자주식회사 Cpu와 gpu를 사용하는 이종 시스템에서 가상화를 이용한 어플리케이션 컴파일 및 실행 방법 및 장치
US8819649B2 (en) * 2011-09-09 2014-08-26 Microsoft Corporation Profile guided just-in-time (JIT) compiler and byte code generation

Non-Patent Citations (1)

* Cited by examiner, † Cited by third party
Title
丸岡 晃 ほか,LLVMを用いたベクトルアクセラレータ用コードのコンパイル手法,情報処理学会 研究報告 システム・アーキテクチャ(ARC) [オンライン],日本,情報処理学会,2016年08月01日,pp.1-6,インターネット:<URL:https://ipsj.ixsq.nii.ac.jp/ej/?action=repository_uri&item_id=172900&file_id=1&

Also Published As

Publication number Publication date
WO2021140568A1 (ja) 2021-07-15
JPWO2021140568A1 (ja) 2021-07-15
US11886839B2 (en) 2024-01-30
US20220261224A1 (en) 2022-08-18

Similar Documents

Publication Publication Date Title
JP4057938B2 (ja) コンパイラ、コンパイル方法、及びプログラム開発ツール
US7596781B2 (en) Register-based instruction optimization for facilitating efficient emulation of an instruction stream
US7917899B2 (en) Program development apparatus, method for developing a program, and a computer program product for executing an application for a program development apparatus
JP7295469B2 (ja) 関数生成プログラム、関数生成方法、及び情報処理装置
KR0125605B1 (ko) 프로그램의 아키덱쳐 변환방법 및 장치와 그 방법 및 장치를 사용하여 프로그램의 동작을 검증하는 방법 및 장치
CN116775127B (zh) 一种基于RetroWrite框架的静态符号执行插桩方法
Hyde The art of assembly language
Bocchino Jr et al. Vector LLVA: a virtual vector instruction set for media processing
CN116594682A (zh) 基于simd库的自动测试方法及装置
Bezzubikov et al. Automatic dynamic binary translator generation from instruction set description
JP7315872B2 (ja) プロセッサ、シミュレータプログラム、アセンブラプログラム、及び情報処理プログラム
JP7295466B2 (ja) クラス生成プログラム及びクラス生成方法
Korenkov et al. Declarative target architecture definition for data-driven development toolchain
Markstedter Blue Fox: Arm Assembly Internals and Reverse Engineering
CN118069142B (zh) 编译优化方法、装置、电子设备及存储介质
WO2024222455A1 (zh) 一种硬件加速指令确定方法、系统、电子设备及存储介质
JP2004013190A (ja) ソフトウエア開発環境、シミュレータ及び記録媒体
US11321094B2 (en) Non-transitory computer-readable medium, assembly instruction conversion method and information processing apparatus
JP3915208B2 (ja) コンパイル装置
Birch An emulator for the e-machine
dos Santos C Compiler and Tools for P3 Educational Processor
Pokale et al. A Petite Guide to Programming in 64bit X86 Assembly Language for Linux
JP2009252170A (ja) コンバータ及びプログラム変換方法
JP2004021441A (ja) プログラム処理装置及びプログラム処理方法、並びにコンピュータ・プログラム
Mráček A decompiler for Objective-C

Legal Events

Date Code Title Description
A621 Written request for application examination

Free format text: JAPANESE INTERMEDIATE CODE: A621

Effective date: 20220511

TRDD Decision of grant or rejection written
A01 Written decision to grant a patent or to grant a registration (utility model)

Free format text: JAPANESE INTERMEDIATE CODE: A01

Effective date: 20230509

A61 First payment of annual fees (during grant procedure)

Free format text: JAPANESE INTERMEDIATE CODE: A61

Effective date: 20230522

R150 Certificate of patent or registration of utility model

Ref document number: 7295469

Country of ref document: JP

Free format text: JAPANESE INTERMEDIATE CODE: R150