LLVM for Grad Students 大学院生のためのLLVM を訳す7

Now Make the Pass Do Something Mildly Interesting

魔法は見つけるときに必要に応じて、コードを変更することとあなたがプログラムのパターンを探したときにあるでしょう。
簡単な例を示します. すべてのfunctionのは最初の二項演算子(+, -等)を乗算する関数全てで交換したいとしましょう。

ここにコードを示す, 現在のバージョンでgitのllvm-pass-skeletonのレポジトリのmutateブランチの中に利用可能である.

for (auto& B : F) {
 for (auto& I : B) {
   if (auto* op = dyn_cast<BinaryOperator>(&I)) {
     // Insert at the point where the instruction `op` appears.
     IRBuilder<> builder(op);
     // Make a multiply with the same operands as `op`.
     Value* lhs = op->getOperand(0);
     Value* rhs = op->getOperand(1);
     Value* mul = builder.CreateMul(lhs, rhs);
     // Everywhere the old instruction was used as an operand, use our
     // new multiply instruction instead.
     for (auto& U : op->uses()) {
       User* user = U.getUser();  // A User is anything with operands.
       user->setOperand(U.getOperandNo(), mul);
     }
     // We modified the code.
     return true;
   }
 }
}

details:

dyn_cast(p)構造体はLLVMの固有のイントロスペクションユーティリティである.
コンパイラは、それらのすべての時間を使用する必要があるため,それはLLVMの効率的動的テストによってつくられたコードベースからいくつかの利用が可能である.
IがBinaryOperatorでない場合、この構造体は、NULLポインタを返すため、特別なケースに最適である.

IR Builderはコードを構築する. それはおそらくあなたが可能となる命令の種類を百万ほど持っています.

コードに新しい命令をつなげるために、引数として、新しい命令内で使われているすべての場所やスワップを見つける必要があります。
命令は値であることを思い出してください. ここで, 乗算命令は他の命令のオペランドで使われる, つまり, 引数としてわたされるということである.

古い命令は削除すべきかもしれないが, 簡潔にするため左ビットシフトを使用します.

いま, このようなプログラムをコンパイルするとします. (レポジトリのexample.c)

#include <stdio.h>
int main(int argc, const char** argv) {
  int num;
  scanf("%i", &num);
  printf("%i\n", num + 2);
  return 0;
}

通常のコンパイラコンパイルするとコード結果を出力することはありませんが, このプラグインを使うことで, 2をたす代わりに2倍にします.

$ cc example.c
$ ./a.out
10
12
$ clang -Xclang -load -Xclang build/skeleton/libSkeletonPass.so example.c
$ ./a.out
10