2016-07-26 6 views
1

元のプログラムの浮動小数点変数の型をlong doubleに変更するために、LLVMパスを作成しています。おもちゃのテストプログラムは次のとおりです:LLVMパスを書いて元のプログラムの浮動小数点変数の型をlong doubleに変更するにはどうすればよいですか?

int main(){ 
    double i = 0.0000000000000001; 
    if(i + 1 > 1) 
     printf("correct answer"); 
    else 
     printf("wrong answer"); 
    return 0; 
} 

私のパスは、 "long double"に変更する必要があります。 元のプログラムのIRと変換されたプログラムの間には5つ​​の異なる場所があります。

< %i = alloca x86_fp80, align 16 
--- 
> %i = alloca double, align 8 

< store x86_fp80 0xK3FC9E69594BEC44DE000, x86_fp80* %i, align 16 
< %0 = load x86_fp80, x86_fp80* %i, align 16 
< %add = fadd x86_fp80 %0, 0xK3FFF8000000000000000 
< %cmp = fcmp ogt x86_fp80 %add, 0xK3FFF8000000000000000 
--- 
> store double 1.000000e-16, double* %i, align 8 
> %0 = load double, double* %i, align 8 
> %add = fadd double %0, 1.000000e+00 
> %cmp = fcmp ogt double %add, 1.000000e+00 

次のように上記の変換を行うには、私のパスの概要は次のとおりです。

virtual bool runOnFunction(Function &F) { 
    std::string svariable ("i"); 
    const ValueSymbolTable& symbolTable = F.getValueSymbolTable(); 
    Value* target = symbolTable.lookup(svariable); 
    AllocaInst* old_target = dyn_cast<AllocaInst>(target); 
    errs() <<"old_target: " << *target << "\n"; 
    errs() <<"num of old_target_uses:" << old_target->getNumUses() <<"\n"; 

    //get the type of long double and construct new AllocaInst 
    LLVMContext &context = F.getContext(); 
    Type* type = Type::getX86_FP80Ty(context); 
    unsigned alignment = 16; 
    AllocaInst* new_target = new AllocaInst(type, 0, alignment, "new", old_target); 
    new_target->takeName(old_target); 

    // iterating through instructions using old AllocaInst 
    Value::use_iterator it = old_target->use_begin(); 
    for(; it != old_target->use_end(); it++) { 
      Value * temp = it->get(); 
      errs() <<"temp:" << *temp <<"\n"; 
      //transform() is under construction 
      transform(it, new_target, type, alignment); 

    } 
    old_target->eraseFromParent(); 
    return false; 
} 

元のプログラムのIRに示したように、私を倍増するために関連する4つの命令がなければならない:

> store double 1.000000e-16, double* %i, align 8 
> %0 = load double, double* %i, align 8 
> %add = fadd double %0, 1.000000e+00 
> %cmp = fcmp ogt double %add, 1.000000e+00 

が、上記予想通りパスの出力はありません:

old_target: %i = alloca double, align 8 
num of old_target_uses:2 
temp: %0 = alloca double, align 8 
temp: %0 = alloca double, align 8 

私の最初の質問は、getNumUses()とuse_iteratorが正解を返さなかった理由です。パスのアウトラインで間違った方法で使用しましたか?

私の2番目の質問は、私のtransform()関数にあります。LoadInst、StoreInst、BinaryOperationなどのあらゆる種類の命令を列挙し、新しい型でそれらを再構築する必要がありますか?最初の質問のように、各Useオブジェクトは、基本的にそのUsers(命令や定数のいずれかにValue(主に命令または定数)を結ぶデータ・フロー・グラフにおけるエッジ予め

感謝:)

+0

は、なぜあなたは(例えば、クランを使用して)LLVMのレベルではなく、ソースコードレベルでこの問題を攻撃することを選択したのですか? – eush77

+0

ご意見ありがとうございました。 LLVMのIRレベルでそれを攻撃すると、C/C++、Fortran、RなどのLLVMをコンパイルする(またはコンパイルする)ソース言語を簡単にサポートできます。 – Sue

答えて

1

あります)。両方の値にはそれぞれUse::getUse::getUserでアクセスできます。ここで

Value::use_iterator it = old_target->use_begin(); 
for(; it != old_target->use_end(); it++) { 
     Value * temp = it->get(); 
} 

、あなたがold_targetの用途に反復処理し、各使用の使用値にtempを割り当てるときに、何を割り当てられているが実際old_targetそのものです。私があなたが信じているのは、it->getUserです。のユーザーになります。

あなたの例では%iが2回使用されているのでgetNumUses()が実際に正しいことに注意してください、storeで初めて、その後、loadインチ私の2番目の質問は、私の変換()関数である

、私は右、 に、このようなLoadInst、StoreInst、BinaryOperation として命令のすべての種類を列挙し、新しいタイプでそれらを再構築する必要がありますか?

実際にタイプを交換する場合は、これはおおよそここで必要とされるものだと思います。一般的にタイプをこのように置き換えると結果が正しくない可能性があるので、最初にbitcastptrtointなどの命令が動作していないことを確認したい場合があります。私はあなたがソースと最初からそれらの上で動作する命令の限られたサブセットのためのallocasをサポートし、ここからサブセットを成長することをお勧めします。

その後、あなたはx86_fp80/x86_fp80*double/double*から種類を変更するそのオペランドのいずれかに対応するための方法で各ユーザーを変換するでしょう。その結果の型が変更された場合は、それを伝播する必要があります。そのためには、ワークリストパターンが役立つかもしれません。つまり、LLVM自体のパス数が整理されています(example)。

IRを更新する通常の手段は、Value::replaceAllUsesWithです。しかし、あなたのケースでは、型が変わる可能性が非常に高くなります。このため、この関数はエラーメッセージで失敗します。したがって、おそらくUser::setOperand,Value::mutateTypeの組み合わせを使用して、必要に応じて新しい指示を作成して、IRとタイプを手動で変更する必要があります。例えば

    loadため
  • faddfcmpと同様の命令、オペランド(単数または複数)を交換してワークリストに結果を追加します。 store命令の
  • :最初のオペランドのタイプが変更された場合に、第2のオペランドのタイプも変更されていない限り
    • 、処理を中止します。
    • 第2オペランドの型が変更されたが、最初の型の型が変更されていない場合は、最初のオペランドをx86_fp80fpext)に変換します。
    • いずれの場合も、結果をワークリストに追加します。 callinvoke手順について
  • (あなたは、このようなダウンキャストを許可しない場合、または中止)、fptruncdoublex86_fp80オペランドをキャスト。
  • bitcastおよびptrtoint命令の場合、処理を中止します。
  • ...
+0

非常に役に立ちます。あなたが言ったように、それはgetUser()でなければなりません。 transform()についての助言をいただきありがとうございます。私は今、それを書く方法をより明確にしています。 – Sue

関連する問題