[llvm-dev] reusing an ExecutionEngine instance

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[llvm-dev] reusing an ExecutionEngine instance

U.Mutlu via llvm-dev
Greetings, LLVM wizards,

I am trying to use Clang to compile a function in memory once, then to execute it several times with different parameters. That is, I want to keep the resulting ExecutionEngine instance around and reuse it. (Or, if there is a better way to do this, I am open to suggestions.) (And if this is not the right mailing list for this kind of question, I am open to suggestions, too.)

In the code below, the ExecutionEngine works fine if I use it immediately. But if I return from the function and use it afterward, I get memory corruption and crashes, presumably because it contains references to something that has been deleted. And in fact, if I change the code so that the CodeGenAction is not deleted, it seems to work.

My question is: why should deleting the CodeGenAction corrupt the ExecutionEngine? Are there other things I should avoid deleting as well? (The following code was adapted from the clang-interpreter example in the v4.0.1 source code.)

Geoff


ExecutionEngine* compile(const std::string& filename)
{
    const char *resource_dir = getenv("CLANG_RESOURCE_DIR");
    if (resource_dir == NULL) {
        std::cerr << "Clang resource directory has not been defined.\n";
        return NULL;
    }

    IntrusiveRefCntPtr<DiagnosticOptions> diag_opts(new DiagnosticOptions);
    TextDiagnosticPrinter *diag_client =
        new TextDiagnosticPrinter(llvm::errs(), diag_opts.get());
    IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs);
    DiagnosticsEngine diags(diag_ids, diag_opts.get(), diag_client);
    std::string executable = "dg2";
    Driver driver(executable, llvm::sys::getDefaultTargetTriple(), diags);

    SmallVector<const char*, 16> args;
    args.push_back(executable.c_str());
    args.push_back(filename.c_str());
    args.push_back("-fsyntax-only");
    args.push_back("-fno-use-cxa-atexit");
    args.push_back("-resource-dir");
    args.push_back(resource_dir);
    args.push_back("-std=c++11");
    args.push_back("-O3");

    std::unique_ptr<Compilation> compilation(driver.BuildCompilation(args));
    const JobList& jobs = compilation->getJobs();
    if (jobs.size() != 1 || !llvm::isa<Command>(*jobs.begin())) {
        std::cerr << "Expected a single Command job from Compilation...\n";
        return NULL;
    }

    const Command& cmd = llvm::cast<Command>(*jobs.begin());
    if (StringRef(cmd.getCreator().getName()) != "clang") {
        std::cerr << "Expected a single clang Command from Compilation...\n";
        return NULL;
    }

    const ArgStringList& ccargs = cmd.getArguments();
    std::unique_ptr<CompilerInvocation> invocation(new CompilerInvocation);
    CompilerInvocation::CreateFromArgs(
        *invocation,
        const_cast<const char**>(ccargs.data()),
        const_cast<const char**>(ccargs.data()) + ccargs.size(),
        diags);

    CompilerInstance clang;
    clang.setInvocation(std::move(invocation));
    clang.createDiagnostics();

    std::unique_ptr<CodeGenAction> action(new EmitLLVMOnlyAction);
    if (!clang.ExecuteAction(*action)) {
        return NULL;
    }
    std::unique_ptr<Module> module(action->takeModule());

    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();

    std::string error;

    ExecutionEngine *exec_engine =
        EngineBuilder(std::move(module))
        .setEngineKind(llvm::EngineKind::Either)
        .setErrorStr(&error)
        .create();

    if (!exec_engine) {
        std::cerr << "Could not create execution engine: " << error << std::endl;
        return NULL;
    }

    exec_engine->finalizeObject();
    return exec_engine;
}


_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|

Re: [llvm-dev] reusing an ExecutionEngine instance

U.Mutlu via llvm-dev
Well, if anybody out there comes across a similar problem, I found the solution: create your own LLVMContext object and pass it to the EmitLLVMOnlyAction constructor. If you don't, CodeGenAction creates a temporary context and deletes it when the CodeGenAction is deleted. And the LLVMContext destructor deletes the module that was created, even though you may have a std::unique_ptr to it...

Geoff

On 4 June 2018 at 14:51, Geoff Levner <[hidden email]> wrote:
Greetings, LLVM wizards,

I am trying to use Clang to compile a function in memory once, then to execute it several times with different parameters. That is, I want to keep the resulting ExecutionEngine instance around and reuse it. (Or, if there is a better way to do this, I am open to suggestions.) (And if this is not the right mailing list for this kind of question, I am open to suggestions, too.)

In the code below, the ExecutionEngine works fine if I use it immediately. But if I return from the function and use it afterward, I get memory corruption and crashes, presumably because it contains references to something that has been deleted. And in fact, if I change the code so that the CodeGenAction is not deleted, it seems to work.

My question is: why should deleting the CodeGenAction corrupt the ExecutionEngine? Are there other things I should avoid deleting as well? (The following code was adapted from the clang-interpreter example in the v4.0.1 source code.)

Geoff


_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev