1

実行時に既存の C/C++ プログラムでいくつかの関数を JIT コンパイルしようとしていますが、グローバル変数の初期化で問題が発生しています。具体的には、Clang を使用して、プログラムを実行可能ファイルに加えて IR ビットコード モジュールにプリコンパイルするという方法をとっています。実行時に、プログラムはモジュールをロードし、変換し (プログラムの特殊化)、コンパイルして実行します。結局のところ、「ホスト」プログラムの実行中に初期化および変更されるグローバル変数がいくつかあります。現在、これらのグローバルも JIT コンパイル コードで初期化されていますが、代わりにホスト グローバル変数にマップされるようにしたいと考えています。誰かがこれで私を助けることができますか?

小さな再現を以下に抜粋します。完全なソース コードはこちらにあります。somefunc.cpp ファイルはビルド中にプリコンパイルされ、testCompile.cpp の main() 関数に読み込まれます。グローバル変数 xyz は somefunc.cpp で 25 を指すように初期化されていますが、代わりに main() のように 10 を指すようにしたいと考えています。つまり、main() のアサーションは成功するはずです。

この問題を解決するために、いくつかの異なる方法を試しました。ChangeGlobal() 関数は、この updateGlobalMapping() を達成しようとします (失敗します)。2 つ目の、よりハックなアプローチでは、適切に初期化された新しいグローバル変数を使用します。この後者のアプローチをいくつかのタイプのグローバルで機能させることができますが、これよりもエレガントなアプローチはありますか?

//————— somefunc.h ————————
extern int *xyz;

//—————— somefunc.cpp ——————
int abc = 25;
int *xyz = &abc;

int somefunc() {
    return *xyz;
}

//—————— testCompile.cpp —————— 
class JitCompiler {
 public:
    JitCompiler(const std::string module_file);
    void LoadModule(const std::string& file);
    template <typename FnType>  
        FnType CompileFunc(FnType fn, const std::string& fn_name);
    void ChangeGlobal();

 private:
    std::unique_ptr<LLVMContext> context_;
    Module *module_;
    std::unique_ptr<ExecutionEngine> engine_;
};

void JitCompiler::ChangeGlobal() {
    // ----------------- #1: UpdateGlobalMapping -----------------
    //auto g = engine_->FindGlobalVariableNamed("xyz");
    //engine_->updateGlobalMapping(g, &xyz);
    //assert(engine_->getGlobalValueAddress("xyz") == (uint64_t) &xyz);

    // ----------------- #2: Replace with new global ————————
    // ------- Ugly hack that works for globals of type T** ----------
    auto g = engine_->FindGlobalVariableNamed("xyz");
    Constant *addr_i = ConstantInt::get(*context_, APInt(64, (uint64_t) xyz));
    auto addr = ConstantExpr::getIntToPtr(
                    addr_i, g->getType()->getPointerElementType());

    GlobalVariable *n = new GlobalVariable(
        *module_,
        g->getType()->getPointerElementType(),
        g->isConstant(),
        g->getLinkage(),
        addr,
        g->getName() + "_new");
    g->replaceAllUsesWith(n);
    n->takeName(g);
    g->eraseFromParent();
}

int main() {
    xyz = new int (10);
    JitCompiler jit("somefunc.bc");

    jit.ChangeGlobal();
    auto fn = jit.CompileFunc(&somefunc, "somefunc");
    assert(somefunc() == fn());
}
4

1 に答える 1

0

より良いアプローチは、あなたが提示した2つの組み合わせです。つまり、外部リンケージがマップされた新しいグローバルを作成し&xyz、元のものに置き換えます。

auto g = engine_->FindGlobalVariableNamed("xyz");

GlobalVariable *n = new GlobalVariable(
  g->getType()->getPointerElementType(),
  g->isConstant(),
  ExternalLinkage
  nullptr,
  g->getName() + "_new");

engine_->updateGlobalMapping(n, &xyz);

g->replaceAllUsesWith(n);
n->takeName(g);
g->eraseFromParent();
于 2016-06-22T21:41:24.677 に答える