2.6/trunk Execution Engine question

I've gotten my front-end to compile with the 2.6 branch and with trunk
(not with both; I have to fiddle with a few things when switching),
and it refuses to give me an execution engine.

My link flags include everything coming from "llvm-config --libs".
Nevertheless, the error string coming back from
ExecutionEngine::create is:

JIT has not been linked in

Is this a known problem? Is there something I should be doing that I
wasn't doing in 2.5?

Hi,

#include "JIT.h" will do.

Cheers, Axel.

Thanks. That was exactly what I needed to progress to the next error
("Unable to find target for this triple (no targets are registered)")

As soon as I get this front-end working with the trunk, I'll start
submitting patches that add calls to the C-API; my front-end generates
code-generation-code that relies on it rather heavily, and there are
gaps I'd like to fill in.

Hi,

#include "JIT.h" will do.

Thanks. That was exactly what I needed to progress to the next error
("Unable to find target for this triple (no targets are registered)")

You probably need to call InitializeNativeTarget() or something. IMO,
LLVM should probably do this by default as part of constructing a JIT.

Reid

My front-end is humming along beautifully now with the LLVM trunk. A
few upgrade notes for anyone who is interested:

1. Not surprisingly, everything in your front-end needs to be
recompiled; object layouts have changed. My generated code was
calling some name-mangled stuff in the C++ libraries, and using
struct/class definitions defined therein, and it fell over hard when I
ran it against the trunk libraries. I ripped all that stuff out and
added what I needed to the C bindings.

2. Linkage enums have changed. Since my front-end doesn't understand
C, I had ported some LLVM definitions over so that I could use them in
my language. That port, of course, was not automatically updated when
I built against the trunk, so I ended up with global linkage settings
that I wasn't expecting. This led to:

3. llc gets very unhappy if you give an unnamed global variable weak
linkage. This is not surprising, since weak linkage uses name
matching and doesn't make sense for things that have no name.
Updating my linkage enum port cleared that up for me.

4. The set of library names to link against has changed considerably.

5. C bindings to ExecutionEngine stuff have moved out of libCore.a.

6. When ExecutionEngine::create was called with parameter
"GVsWithCode" set to its default value of true, I got a segfault when
trying to get a pointer to one of my globals. JIT::getMemoryForGV was
returning NULL in that case. Explicitly passing false for
"GVsWithCode" cleared it up.

6. When ExecutionEngine::create was called with parameter
"GVsWithCode" set to its default value of true, I got a segfault when
trying to get a pointer to one of my globals. JIT::getMemoryForGV was
returning NULL in that case. Explicitly passing false for
"GVsWithCode" cleared it up.

That's no good. Could you send me a stack trace and explain how you
got that to happen? I was the last one to touch that code.

In your case, I would definitely set that parameter to false. For
some reason, OpenCL requires that code and globals be allocated
together contiguously, and because backwards compatibility with them
is somehow more important than doing the right thing, that's still the
default behavior. See http://llvm.org/bugs/show_bug.cgi?id=4483 .

Reid

Stack trace attached. It's not very informative; it just tells us
that it's got a null pointer that it thinks is a pointer to the
global, and it's trying to initialize that global.

What I did was load a module from a MemoryBuffer, use an
ExistingModuleProvider to feed it to the ExecutionEngine, then start
looping through its globals and get their addresses so I can refer to
their values while compiling another module. The segfault happened on
the first one it encountered, a linkonce constant int32.

I can try and reduce it for you if you need. The comment above create
said that passing true was "unsafe", so I figured it was a known issue
and plowed ahead with the upgrade.

morenotes.txt (693 Bytes)

Also, the null pointer is coming from a call to JCE->allocateSpace().
This is a virtual function; I'm trying to discover what subclass it
is.

It just occurred to me... in the case where it's failing, the
ExecutionEngine was trying to JIT a global, and it had never JITted
any functions! I'll work up a small test case, but I think it's
relevant since the thing is trying to allocate the globals with the
functions.

It just occurred to me... in the case where it's failing, the
ExecutionEngine was trying to JIT a global, and it had never JITted
any functions! I'll work up a small test case, but I think it's
relevant since the thing is trying to allocate the globals with the
functions.

That was it! The following small test program crashes in getPointerToGlobal:

#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/InlineAsm.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/raw_os_ostream.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetSelect.h"
#include "llvm/ExecutionEngine/JIT.h"

#include <assert.h>

using namespace llvm;

static raw_stdout_ostream raw_cout;

int main(int argc, char** argv)
{
  // Test JITting a variable without JITting any functions.'
  Module* mod = new Module("test", getGlobalContext());
  GlobalVariable* gv = cast<GlobalVariable>(mod->getOrInsertGlobal("TestGV",
      Type::getInt32Ty(getGlobalContext())));
  gv->setInitializer(ConstantInt::get(
    Type::getInt32Ty(getGlobalContext()), 24601));

  ModuleProvider* modp = new ExistingModuleProvider(mod);
  InitializeNativeTarget();
  std::string errstring;

  ExecutionEngine* eeng = ExecutionEngine::create(modp, false, &errstring,
      CodeGenOpt::Default, true);
  if ( eeng == NULL )
  {
    raw_cout << errstring << "\n";
    exit(-1);
  }
  raw_cout << "Fixing to get pointer to global\n";
  void* gvp = eeng->getPointerToGlobal(gv);
  raw_cout << "Got pointer to global\n";
  raw_cout << "gv = " << *((int*)gvp) << "\n";
  exit(0);
}

And I should not forget to mention that passing "true" as the last
parameter to ExecutionEngine::create makes the test program work and
finish with the output line "gv = 24601"