Deploy ushitora-anqou/write-your-llvm-backend to github.com/ushitora-anqou/write-your-llvm-backend.git:gh-pages

This commit is contained in:
Ushitora Anqou (via Travis CI) 2020-04-01 08:00:49 +00:00
parent e765ed0812
commit 0c40bf8e8a

View File

@ -477,7 +477,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
<li><a href="#_cahpinstprinter_を実装する"><code>CAHPInstPrinter</code> を実装する</a></li> <li><a href="#_cahpinstprinter_を実装する"><code>CAHPInstPrinter</code> を実装する</a></li>
<li><a href="#_テストを書く">テストを書く</a></li> <li><a href="#_テストを書く">テストを書く</a></li>
<li><a href="#_メモリ演算を追加する">メモリ演算を追加する</a></li> <li><a href="#_メモリ演算を追加する">メモリ演算を追加する</a></li>
<li><a href="#_属性を指定する">属性を指定する</a></li> <li><a href="#_フィールドを詳細に指定する">フィールドを詳細に指定する</a></li>
<li><a href="#_ディスアセンブラを実装する">ディスアセンブラを実装する</a></li> <li><a href="#_ディスアセンブラを実装する">ディスアセンブラを実装する</a></li>
<li><a href="#_relocationとfixupに対応する">relocationとfixupに対応する</a></li> <li><a href="#_relocationとfixupに対応する">relocationとfixupに対応する</a></li>
<li><a href="#_hi_と_lo_に対応する"><code>%hi</code><code>%lo</code> に対応する</a></li> <li><a href="#_hi_と_lo_に対応する"><code>%hi</code><code>%lo</code> に対応する</a></li>
@ -581,8 +581,8 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
<h2 id="_この文書について">この文書について</h2> <h2 id="_この文書について">この文書について</h2>
<div class="sectionbody"> <div class="sectionbody">
<div class="paragraph"> <div class="paragraph">
<p>この文書はhttps://asciidoctor.org/[Asciidoctor]を用いて執筆されています。 <p>この文書は <a href="https://asciidoctor.org/">Asciidoctor</a>を用いて執筆されています。
記述方法はhttps://asciidoctor.org/docs/user-manual/[Asciidoctor User Manual] 記述方法は <a href="https://asciidoctor.org/docs/user-manual/">Asciidoctor User Manual</a>
参考にしてください。</p> 参考にしてください。</p>
</div> </div>
<div class="paragraph"> <div class="paragraph">
@ -1397,7 +1397,7 @@ TableGenにエンコードの処理を移譲することができます<sup clas
<div class="paragraph"> <div class="paragraph">
<p>なおTableGenでは <code>let</code> で囲むレコードが一つの場合は括弧 <code>{ }</code> は必要ありません。 <p>なおTableGenでは <code>let</code> で囲むレコードが一つの場合は括弧 <code>{ }</code> は必要ありません。
また <code>let</code> で外からフィールドを上書きするのと、 <code>def</code> の中身に記載するのとで意味は また <code>let</code> で外からフィールドを上書きするのと、 <code>def</code> の中身に記載するのとで意味は
変わりません。すなわち、上のコードは次の2通りと意味は異なりません<a href="#llvm-tablegen">[21]</a></p> 変わりません。すなわち、上のコードは次の2通りと意味は異なりません<a href="#llvm-tablegen-langref">[25]</a></p>
</div> </div>
<div class="literalblock"> <div class="literalblock">
<div class="content"> <div class="content">
@ -1495,8 +1495,8 @@ CAHPではx0を表す <code>CAHP::X0</code> を渡すことになります。</p
</div> </div>
<div class="paragraph"> <div class="paragraph">
<p><code>CAHPAsmBackend</code> にはオブジェクトファイルを作成する際に必要な <p><code>CAHPAsmBackend</code> にはオブジェクトファイルを作成する際に必要な
fixupの操作や指定バイト数分の無効命令を書き出す処理などを記述します。 fixupの操作 <code>applyFixup</code> や指定バイト数分の無効命令を書き出す処理 <code>writeNopData</code>
<code>MCTargetDesc/CAHPAsmBackend.cpp</code> に記述します。 などを記述します。 <code>MCTargetDesc/CAHPAsmBackend.cpp</code> に記述します。
fixupについては後ほど実装するためここではスタブにしておきます。</p> fixupについては後ほど実装するためここではスタブにしておきます。</p>
</div> </div>
<div class="paragraph"> <div class="paragraph">
@ -1523,38 +1523,387 @@ bin/llvm-mc: error: this target does not support assembly parsing.</pre>
</div> </div>
<div class="paragraph"> <div class="paragraph">
<p>このようなエラーメッセージが出れば成功です<sup class="footnote">[<a id="_footnoteref_9" class="footnote" href="#_footnotedef_9" title="View footnote.">9</a>]</sup> <p>このようなエラーメッセージが出れば成功です<sup class="footnote">[<a id="_footnoteref_9" class="footnote" href="#_footnotedef_9" title="View footnote.">9</a>]</sup>
続いてアセンブリをパーズする部分を開発します。</p> このエラーメッセージはCAHPターゲットがアセンブリのパーズ構文解析に対応していない
ことを意味しています。これは次の節で実装します。</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>RISC-Vの拡張C命令には <code>add</code> などレジスタを5bitで指定する命令と、
<code>sub</code> などレジスタを3bitで指定する命令の2種類があります。
LLVM RISC-Vバックエンドを見ると、
エンコードに際してこれらの区別のための特別な処理は行っていません。
というのも、3bitでレジスタを指定する場合その添字の下位3bit以外が無視されるため、
結果的に正しいコードが出力されるのです。
例えば <code>x8</code> を指定すると、これに <code>1000</code> という添字が振られ、
4bit目を無視することで <code>000</code> となるため、
3bitでのレジスタ指定方法として正しいものになります。</p>
</div>
<div class="paragraph">
<p>独自ISAなどで、このような手法が取れないレジスタの並びを使用する場合は、
アセンブリをコードに変換する際にそのレジスタのエンコーディングを補正します。
このようなレジスタオペランドエンコードのフックを行う関数を指定する場所として
<code>RegisterOperand</code><code>EncoderMethod</code> があります。
例えば <code>sub</code><code>X3</code> から <code>X10</code> を0〜7というエンコードで用いたい場合、
<code>X3</code> から <code>X10</code><code>GPRC</code> という <code>RegisterClass</code> とした上で、
これを <code>RegisterOperand</code> で包み <code>ShiftedGPRC</code> とします。
これの <code>EncoderMethod</code> として <code>RV32KEncodeShiftedGPRCRegisterOperand</code> という関数を指定します。
これは <code>RV32KMCCodeEmitter</code> クラスのメンバ関数として定義する。
これによって任意の処理をフックすることができる。https://reviews.llvm.org/rL303044</p>
</div>
<div class="literalblock">
<div class="content">
<pre>def GPRC : RegisterClass&lt;"RV32K", [i32], 32, (add
X3, X4, X5, X6, X7, X8, X9, X10
)&gt;;
def ShiftedGPRC : RegisterOperand&lt;GPRC&gt; {
let EncoderMethod = "RV32KEncodeShiftedGPRCRegisterOperand";
//let DecoderMethod = "RV32KDecodeShiftedGPRCRegisterOperand";
}</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>uint64_t
RV32KEncodeShiftedGPRCRegisterOperand(const MCInst &amp;MI, unsigned no,
SmallVectorImpl&lt;MCFixup&gt; &amp;Fixups,
const MCSubtargetInfo &amp;STI) const;
uint64_t RV32KMCCodeEmitter::RV32KEncodeShiftedGPRCRegisterOperand(
const MCInst &amp;MI, unsigned no, SmallVectorImpl&lt;MCFixup&gt; &amp;Fixups,
const MCSubtargetInfo &amp;STI) const {
const MCOperand &amp;MO = MI.getOperand(no);
if (MO.isReg()) {
uint64_t op = Ctx.getRegisterInfo()-&gt;getEncodingValue(MO.getReg());
assert(3 &lt;= op &amp;&amp; op &lt;= 10 &amp;&amp; "op should belong to GPRC.");
return op - 3;
}
llvm_unreachable("Unhandled expression!");
return 0;
}</pre>
</div>
</div>
</td>
</tr>
</table>
</div> </div>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_cahpasmparser_を追加する"><code>CAHPAsmParser</code> を追加する</h3> <h3 id="_cahpasmparser_を追加する"><code>CAHPAsmParser</code> を追加する</h3>
<div class="paragraph"> <div class="paragraph">
<p>アセンブリのパーズは <code>CAHPAsmParser</code> が取り仕切っています。</p> <p>アセンブリのパーズは <code>CAHPAsmParser</code> クラスが取り仕切っています。
新しく <code>AsmParser</code> ディレクトリを作成し、その中に <code>CAHPAsmParser.cpp</code> を作成して
パーズ処理を記述します。<a href="#github_riscv-llvm_patch_07">[19]</a>を参考にします。</p>
</div>
<div class="paragraph">
<p><code>CAHPAsmParser::ParseInstruction</code> がパーズ処理のエントリポイントです。
<code>CAHPAsmParser::parseOperand</code><code>CAHPAsmParser::parseRegister</code>
<code>CAHPAsmParser::parseImmediate</code> を適宜用いながら、
アセンブリのトークンを切り出し <code>Operands</code> に詰め込みます<sup class="footnote">[<a id="_footnoteref_10" class="footnote" href="#_footnotedef_10" title="View footnote.">10</a>]</sup></p>
</div>
<div class="paragraph">
<p>この際にオペランドを表すクラスとして <code>CAHPOperand</code> を定義・使用しています。
オペランドとして現れうるのはレジスタと即値とその他のトークン(命令や括弧文字など)なので
その旨を記述します<sup class="footnote">[<a id="_footnoteref_11" class="footnote" href="#_footnotedef_11" title="View footnote.">11</a>]</sup>
TableGenにて定義・使用した即値を正しく認識するために <code>isUImm4</code><code>isSImm11Lsb0</code> などの
メンバ関数を定義する必要があります。これらの関数は後述の <code>MatchInstructionImpl</code> 内で
使用されます。</p>
</div>
<div class="paragraph">
<p>切り出されたオペランドのリストを命令としてLLVMに認識させるのは <code>MatchAndEmitInstruction</code>
行います。具体的には、先程の <code>Operands</code> を読み込んで <code>MCInst</code> に変換します。
ただし実際の処理の殆どはTableGenによって自動生成された <code>MatchInstructionImpl</code> によって
行われます。実際に書く必要があるのはこの関数が失敗した場合のエラーメッセージ等です。</p>
</div>
<div class="paragraph">
<p><code>CAHPAsmParser</code> を実装するとアセンブラが完成します。使ってみましょう。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>$ cat foo.s
li x9, 3
mv x11, x1
sub x9, x10
add x8, x1
nop
$ bin/llvm-mc -arch=rv32k -filetype=obj foo.s | od -tx1z -Ax -v
000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 &gt;.ELF............&lt;
000010 01 00 f5 00 01 00 00 00 00 00 00 00 00 00 00 00 &gt;................&lt;
000020 68 00 00 00 00 00 00 00 34 00 00 00 00 00 28 00 &gt;h.......4.....(.&lt;
000030 04 00 01 00 8d 44 86 85 89 8c 06 94 01 00 00 00 &gt;.....D..........&lt;
000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &gt;................&lt;
000050 00 2e 74 65 78 74 00 2e 73 74 72 74 61 62 00 2e &gt;..text..strtab..&lt;
000060 73 79 6d 74 61 62 00 00 00 00 00 00 00 00 00 00 &gt;symtab..........&lt;
000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &gt;................&lt;
000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &gt;................&lt;
000090 07 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 &gt;................&lt;
0000a0 50 00 00 00 17 00 00 00 00 00 00 00 00 00 00 00 &gt;P...............&lt;
0000b0 01 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 &gt;................&lt;
0000c0 06 00 00 00 00 00 00 00 34 00 00 00 0a 00 00 00 &gt;........4.......&lt;
0000d0 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 &gt;................&lt;
0000e0 0f 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 &gt;................&lt;
0000f0 40 00 00 00 10 00 00 00 01 00 00 00 01 00 00 00 &gt;@...............&lt;
000100 04 00 00 00 10 00 00 00 &gt;........&lt;
000108</pre>
</div>
</div>
<div class="paragraph">
<p>0x34から0x3dにある <code>8d 44 86 85 89 8c 06 94 01 00</code> が出力であり、
正しく生成されていることが分かります。</p>
</div> </div>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_cahpinstprinter_を実装する"><code>CAHPInstPrinter</code> を実装する</h3> <h3 id="_cahpinstprinter_を実装する"><code>CAHPInstPrinter</code> を実装する</h3>
<div class="paragraph">
<p><a href="https://github.com/virtualsecureplatform/llvm-cahp/commit/aa66568c3dfe1d80a83a96bd0437a26fdb96872a">aa66568c3dfe1d80a83a96bd0437a26fdb96872a</a></p>
</div>
<div class="paragraph">
<p>次の節では、上記までで作成したアセンブラのテストを記述します。
その際、アセンブリを <code>MCInst</code> に変換した上でそれをアセンブリに逆変換したものが、
もとのアセンブリと同じであるか否かをチェックします。
このテストを行うためには <code>MCInst</code> からアセンブリを得るための仕組みが必要です。
この節ではこれを行う <code>CAHPInstPrinter</code> クラスを実装します。
<a href="#github_riscv-llvm_patch_08">[20]</a>を参考にします。</p>
</div>
<div class="paragraph">
<p><code>InstPrinter</code> ディレクトリを作成し <code>InstPrinter/CAHPInstPrinter.{cpp,h}</code> を作成します。
命令印字処理の本体は <code>CAHPInstPrinter::printInst</code> ですが、
そのほとんどの処理は <code>CAHPInstPrinter::printInstruction</code> というTableGenが生成する
メンバ関数により実行されます。 <code>CAHPInstPrinter::printRegName</code> はレジスタ名を
出力する関数で <code>CAHPInstPrinter::printOperand</code> から呼ばれますが、
これも <code>CAHPInstPrinter::getRegisterName</code> という自動生成された
メンバ関数に処理を移譲します。この <code>CAHPInstPrinter::getRegisterName</code> の第二引数に
何も渡さなければ(デフォルト引数 <code>CAHP::ABIRegAltName</code> を利用すれば)
TableGenで定義したAltNameが出力に使用されます<sup class="footnote">[<a id="_footnoteref_12" class="footnote" href="#_footnotedef_12" title="View footnote.">12</a>]</sup>
<code>CAHP::NoRegAltName</code> を渡すと本来の名前CAHPでは <code>x0</code><code>x15</code> )が使用されます。</p>
</div>
<div class="paragraph">
<p><code>CAHPInstPrinter</code> クラスは <code>MCTargetDesc/CAHPMCTargetDesc.cpp</code> にて作成・登録されます。</p>
</div>
<div class="paragraph">
<p>節の冒頭で説明した「アセンブリを <code>MCInst</code> に変換した上でそれをアセンブリに逆変換」は
<code>llvm-mc</code><code>-show-encoding</code> オプションを用いて行うことができます。
<code>-show-encoding</code> を指定することよって当該アセンブリがどのような機械語に
翻訳されるか確認することができます。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>$ cat foo.s
// FIXME
$ bin/llvm-mc -arch=rv32k -show-encoding foo.s
.text
li x9, 3 # encoding: [0x8d,0x44]
mv x11, x1 # encoding: [0x86,0x85]
sub x9, x10 # encoding: [0x89,0x8c]
add x8, x1 # encoding: [0x06,0x94]
nop # encoding: [0x01,0x00]</pre>
</div>
</div>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_テストを書く">テストを書く</h3> <h3 id="_テストを書く">テストを書く</h3>
<div class="paragraph">
<p><a href="https://github.com/virtualsecureplatform/llvm-cahp/commit/c8bbf894c7ba046ddd3f55677f2d4512dd944aa0">c8bbf894c7ba046ddd3f55677f2d4512dd944aa0</a></p>
</div>
<div class="paragraph">
<p>前節で動作させた <code>-show-encoding</code> オプションを用いて、
アセンブラが正しく動作していることを確認するためのテストを記述します。
前節と同様にパッチ<a href="#github_riscv-llvm_patch_08">[20]</a>を参考にします。</p>
</div>
<div class="paragraph">
<p>まず <code>test/MC/CAHP</code> ディレクトリを作成し、その中に <code>cahp-valid.s</code><code>cahp-invalid.s</code>
作成します。前者で正しいアセンブリが適切に処理されるか、
後者で誤ったアセンブリに正しくエラーを出力するかを確認します。</p>
</div>
<div class="paragraph">
<p>記述後 <code>llvm-lit</code> を用いてテストを行います。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>$ bin/llvm-lit -as --filter 'RV32K' test
PASS: LLVM :: MC/RV32K/rv32k-valid.s (1 of 2)
Script:
--
: 'RUN: at line 1'; /home/anqou/workspace/llvm-project/build/bin/llvm-mc /data/anqou/workspace/llvm-project/llvm/test/MC/RV32K/rv32k-valid.s -triple=rv32k -show-encoding | /home/anqou/workspace/llvm-project/build/bin/FileCheck -check-prefixes=CHECK,CHECK-INST /data/anqou/workspace/llvm-project/llvm/test/MC/RV32K/rv32k-valid.s
--
Exit Code: 0
********************
PASS: LLVM :: MC/RV32K/rv32k-invalid.s (2 of 2)
Script:
--
: 'RUN: at line 1'; not /home/anqou/workspace/llvm-project/build/bin/llvm-mc -triple rv32k &lt; /data/anqou/workspace/llvm-project/llvm/test/MC/RV32K/rv32k-invalid.s 2&gt;&amp;1 | /home/anqou/workspace/llvm-project/build/bin/FileCheck /data/anqou/workspace/llvm-project/llvm/test/MC/RV32K/rv32k-invalid.s
--
Exit Code: 0
********************
Testing Time: 0.11s
Expected Passes : 2</pre>
</div>
</div>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_メモリ演算を追加する">メモリ演算を追加する</h3> <h3 id="_メモリ演算を追加する">メモリ演算を追加する</h3>
<div class="paragraph">
<p><a href="https://github.com/virtualsecureplatform/llvm-cahp/commit/43145f861dc729756a8a85df13a7257248e98169">43145f861dc729756a8a85df13a7257248e98169</a></p>
</div>
<div class="paragraph">
<p>前節までで、レジスタのみを使用する命令に対応しました。この節ではメモリを使用する
命令に対応します。具体的にはメモリから1ワード2バイト読み込む <code>lw</code>
1ワード書き込む <code>sw</code> 、及びその1バイト版である <code>lb/lbu/sb</code>
更にスタックへの読み書きに特化した <code>lwsp/swsp</code> を追加します。</p>
</div>
<div class="paragraph">
<p>まずTableGenにこれらの命令を定義します。
CAHPアセンブリ中ではメモリは即値とレジスタの組み合わせで表現されます。
例えば <code>x8</code> に入っている値に <code>4</code> 足した番地から1ワード読み込んで <code>x9</code> に入れる場合は
<code>lw x9, 4(x8)</code> と書きます。これを正しく表示するために <code>AsmString</code> にはこのように書きます。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>def LW : CAHPInst24MLoad &lt;0b010101, (outs GPR:$rd), (ins GPR:$rs, simm11_lsb0:$imm),
"lw", "$rd, ${imm}(${rs})"&gt;</pre>
</div>
</div>
<div class="paragraph">
<p>ここで <code>${imm}</code> と括弧でくくっているのは、単に <code>$imm(</code> とかくと <code>imm(</code> という識別子として
認識されてしまうためです。</p>
</div>
<div class="paragraph">
<p>次いでこれらのアセンブリをパーズできるように <code>CAHPAsmParser</code> に手を加えます。
<code>CAHPAsmParser::parseMemOpBaseReg</code> メンバ関数を定義してメモリ指定のアセンブリである
<code>即値(レジスタ)</code> という形を読み込めるようにし、これを <code>CAHPAsmParser::parseOperand</code> から
呼び出します。</p>
</div>
<div class="paragraph">
<p>最後にテストを書きます。</p>
</div>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_属性を指定する">属性を指定する</h3> <h3 id="_フィールドを詳細に指定する">フィールドを詳細に指定する</h3>
<div class="paragraph">
<p><a href="https://github.com/virtualsecureplatform/llvm-cahp/commit/1963e0288a450c3785723861c7c5d5c7280186fc">1963e0288a450c3785723861c7c5d5c7280186fc</a></p>
</div>
<div class="paragraph">
<p>各命令がどのような特性を持つかをTableGenで指定します。
この情報はコード生成の際に使用されます。
これらのフィールドは <code>llvm/include/llvm/Target/Target.td</code>
にてコメントとともに定義されています。</p>
</div>
<div class="paragraph">
<p>以下に主要なフィールドについて説明します。</p>
</div>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_ディスアセンブラを実装する">ディスアセンブラを実装する</h3> <h3 id="_ディスアセンブラを実装する">ディスアセンブラを実装する</h3>
<div class="paragraph">
<p><a href="https://github.com/virtualsecureplatform/llvm-cahp/commit/01fdfc0e1a5281527e339913ee08cb0da9d75f46">01fdfc0e1a5281527e339913ee08cb0da9d75f46</a></p>
</div>
<div class="paragraph">
<p><a href="#github_riscv-llvm_patch_10">[16]</a>を参考にしてディスアセンブラを実装します。
<code>Disassembler</code> ディレクトリを作成して <code>Disassembler/CAHPDisassembler.cpp</code>
を追加・記述します。</p>
</div>
<div class="paragraph">
<p>ディスアセンブラの本体は <code>CAHPDisassembler::getInstruction</code> です。
ディスアセンブルの処理のほとんどはTableGenが生成する <code>decodeInstruction</code> 関数によって
行われます。CAHPでは24bitの命令と16bitの命令が混在するため、
バイナリ列を解析してどちらの命令かを判断し、 <code>decodeInstruction</code> の第一引数に
渡すテーブルを選びます。</p>
</div>
<div class="paragraph">
<p>レジスタのディスアセンブルは <code>DecodeGPRRegisterClass</code> にて行います。</p>
</div>
<div class="paragraph">
<p>即値のディスアセンブルは <code>decodeUImmOperand</code><code>decodeSImmOperand</code> にて
行います。これらの関数は <code>CAHPInstrInfo.td</code> にて 即値オペランドの <code>DecoderMethod</code> として
指定します。</p>
</div>
<div class="paragraph">
<p>ナイーブに実装すると <code>lwsp</code><code>swsp</code> が入ったバイナリをディスアセンブルしようとしたときに
エラーがでる。これは例えば次のようにして確認することができる。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>$ cat test.s
lwsp x11, 0(sp)
$ bin/llvm-mc -filetype=obj -triple=rv32k &lt; test.s | bin/llvm-objdump -d -</pre>
</div>
</div>
<div class="paragraph">
<p>原因は <code>lwsp</code><code>swsp</code> がアセンブリ上はspというオペランドをとるにも関わらず、
バイナリにはその情報が埋め込まれないためである。このためディスアセンブル時に
オペランドが一つ足りない状態になり、配列の添字チェックに引っかかってしまう。</p>
</div>
<div class="paragraph">
<p>これを修正するためには <code>lwsp</code><code>swsp</code> に含まれる即値のDecoderが呼ばれたときをフックし、
<code>sp</code> のオペランドが必要ならばこれを補えばよい<sup class="footnote">[<a id="_footnoteref_13" class="footnote" href="#_footnotedef_13" title="View footnote.">13</a>]</sup>
この関数を <code>addImplySP</code> という名前で実装する。ここで即値をオペランドに追加するために呼ぶ
<code>Inst.addOperand</code><code>addImplySP</code> の呼び出しの順序に注意が必要である。
すなわち <code>LWSP</code><code>CAHPInstrInfo.td</code> で定義したときのオペランドの順序で呼ばなければ
<code>lwsp x11, sp(0)</code> のようなおかしなアセンブリが生成されてしまう。</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>ちなみにエンコード方式にコンフリクトがある場合はビルド時に教えてくれる。</p>
</div>
<div class="literalblock">
<div class="content">
<pre>Decoding Conflict:
111...........01
111.............
................
BNEZ 111___________01
BNEZhoge 111___________01</pre>
</div>
</div>
<div class="paragraph">
<p>これを防ぐためには、もちろん異なるエンコード方式を指定すればよいのだが、
他にディスアセンブル時に命令を無効化する方法としてTableGenファイルで
<code>isPseudo = 1</code> を指定して疑似命令にしたり
<code>isCodeGen = 1</code> を指定してコード生成時にのみ効力を持つ
命令にすることなどができる。</p>
</div>
</td>
</tr>
</table>
</div>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_relocationとfixupに対応する">relocationとfixupに対応する</h3> <h3 id="_relocationとfixupに対応する">relocationとfixupに対応する</h3>
<div class="paragraph">
<p><a href="https://github.com/virtualsecureplatform/llvm-cahp/commit/a03e70e9157510937ca522f14ca0c64c61d47ca7">a03e70e9157510937ca522f14ca0c64c61d47ca7</a></p>
</div>
<div class="paragraph">
<p>ワンパスでは決められない値についてあとから補うための機構であるfixupと、
コンパイル時には決定できない値に対してリンカにその処理を任せるためのrelocationについて
対応する。参考にするパッチは<a href="#github_riscv-llvm_patch_11">[27]</a></p>
</div>
<div class="paragraph">
<p>必要な作業は大きく分けて次の通り。
* Fixupの種類とその内容を定義する。
* Fixupを適用する関数を定義する。
* アセンブラがFixupを生成するように改変する。
* Fixupが解決されないまま最後まで残る場合は、これをrelocationに変換する。</p>
</div>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_hi_と_lo_に対応する"><code>%hi</code><code>%lo</code> に対応する</h3> <h3 id="_hi_と_lo_に対応する"><code>%hi</code><code>%lo</code> に対応する</h3>
@ -2283,10 +2632,22 @@ bin/llvm-mc: error: this target does not support assembly parsing.</pre>
<div class="footnote" id="_footnotedef_9"> <div class="footnote" id="_footnotedef_9">
<a href="#_footnoteref_9">9</a>. 失敗した場合は assertなどで異常終了し、スタックトレースなどが表示されます。 <a href="#_footnoteref_9">9</a>. 失敗した場合は assertなどで異常終了し、スタックトレースなどが表示されます。
</div> </div>
<div class="footnote" id="_footnotedef_10">
<a href="#_footnoteref_10">10</a>. なお以下では しばらくの間、命令を表す <code>add</code> などの文字列そのものも「オペランド」として扱います。
</div>
<div class="footnote" id="_footnotedef_11">
<a href="#_footnoteref_11">11</a>. なおラベルなどの識別子がオペランドに来るアセンブリには まだ対応していませんが、後ほど対応する際にはトークンではなく 即値として対応することになります。
</div>
<div class="footnote" id="_footnotedef_12">
<a href="#_footnoteref_12">12</a>. この場合 <code>AltNames</code> が指定されていないレジスタ(条件分岐のためのフラグなど)があるとエラーとなります。 アセンブリ中に表示され得ないレジスタにもダミーの名前をつける必要があります。
</div>
<div class="footnote" id="_footnotedef_13">
<a href="#_footnoteref_13">13</a>. この実装手法はRISC Vのそれによる。かなりad-hocだと感じるが、他の方法が分からないのでとりあえず真似る。
</div>
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2020-03-31 13:19:48 UTC Last updated 2020-04-01 08:00:26 UTC
</div> </div>
</div> </div>
<script type="text/x-mathjax-config"> <script type="text/x-mathjax-config">