lli crashes when running cpp programs

Hi all,

I need to run c++ prgrams using lli. However, I find lli cannot handle the alias instruction correctly. Following is an example:

------------ example.cc -------------

#include
using namespace std;

class cls {
public:
cls();
~cls();
};

cls::cls() {
cout << “constructor” << endl;
};

cls::~cls() {
cout << “destructor” << endl;
}

int main(int argc, char *argv)
{
cls *A = new cls();
delete A;
return 0;
}

----------- end of file -----------

I compile and run the program by:

$ clang++ -emit-llvm -S example.cc -o example.S
$ llvm-as example.S -o example.bc
$ lli example.bc

and get the “Recursive compilation” error output:

lli: /home/dongpeng/Program/llvm/lib/ExecutionEngine/JIT/JIT.cpp:467: void llvm::JIT::runJITOnFunctionUnlocked(llvm::Function*, const llvm::MutexGuard&): Assertion `!isAlreadyCodeGenerating && “Error: Recursive compilation detected!”’ failed.
0 lli 0x0000000001323d37 llvm::sys::PrintStackTrace(_IO_FILE*) + 38
1 lli 0x0000000001323fbe
2 lli 0x0000000001323a02
3 libpthread.so.0 0x00007fd4c168b210
4 libc.so.6 0x00007fd4c06de1d5 gsignal + 53
5 libc.so.6 0x00007fd4c06e1388 abort + 328
6 libc.so.6 0x00007fd4c06d7252
7 libc.so.6 0x00007fd4c06d7302
8 lli 0x0000000000cf1620 llvm::JIT::runJITOnFunctionUnlocked(llvm::Function*, llvm::MutexGuard const&) + 66
9 lli 0x0000000000cf1a3a llvm::JIT::getPointerToFunction(llvm::Function*) + 694
10 lli 0x00000000010fb64c llvm::ExecutionEngine::getPointerToGlobal(llvm::GlobalValue const*) + 70
11 lli 0x0000000000cfa2f0
12 lli 0x0000000000cfaca3
13 lli 0x00000000008c9368
14 lli 0x0000000000d6a9e1 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 95
15 lli 0x000000000129a53f llvm::FPPassManager::runOnFunction(llvm::Function&) + 385
16 lli 0x000000000129a286 llvm::legacy::FunctionPassManagerImpl::run(llvm::Function&) + 84
17 lli 0x0000000001299e5e llvm::legacy::FunctionPassManager::run(llvm::Function&) + 180
18 lli 0x0000000000cf175c llvm::JIT::jitTheFunction(llvm::Function*, llvm::MutexGuard const&) + 72
19 lli 0x0000000000cf1637 llvm::JIT::runJITOnFunctionUnlocked(llvm::Function*, llvm::MutexGuard const&) + 89
20 lli 0x0000000000cf1a3a llvm::JIT::getPointerToFunction(llvm::Function*) + 694
21 lli 0x0000000000817815 main + 4732
22 libc.so.6 0x00007fd4c06ca995 __libc_start_main + 245
23 lli 0x000000000080d479
Stack dump:
0. Program arguments: lli example.bc

  1. Running pass ‘X86 Machine Code Emitter’ on function ‘@main
    Aborted

I look into the problem and find that it is caused by the alias instructions:

@_ZN3clsC1Ev = alias void (%class.cls*)* @_ZN3clsC2Ev
@_ZN3clsD1Ev = alias void (%class.cls*)* @_ZN3clsD2Ev

The first alias is for the constructor and the other one is for the destructor. When finishing JIT the main function, JITEmitter needs to resolve all the names in main. When it is trying to resolve the alias name @_ZN3clsC1Ev, the following code in JITEmitter.cpp will go to resolve and JIT the original name of the alias name. In my case, they are @_ZN3clsC2Ev and @_ZN3clsD2Ev. This procedure will cause a recursive compilation error.

---------------- lib/ExecutionEngine/JIT/JITEmitter.cpp ------------------------

void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference,
bool MayNeedFarStub) {
if (GlobalVariable *GV = dyn_cast(V))
return TheJIT->getOrEmitGlobalVariable(GV);

if (GlobalAlias *GA = dyn_cast(V))
return TheJIT->getPointerToGlobal(GA->resolveAliasedGlobal(false));

One possible solution is to let JITEmitter emit a stub for the name like following:

@@ -687,8 +687,19 @@
if (GlobalVariable *GV = dyn_cast(V))
return TheJIT->getOrEmitGlobalVariable(GV);

  • if (GlobalAlias *GA = dyn_cast(V))
  • return TheJIT->getPointerToGlobal(GA->resolveAliasedGlobal(false));
  • if (GlobalAlias *GA = dyn_cast(V)) {
  • Function F = const_cast<Function>(dyn_cast(GA->resolveAliasedGlobal(false)));
  • if (F == NULL) {
  • return TheJIT->getPointerToGlobal(GA->resolveAliasedGlobal(false));
  • } else {
  • void *FnStub = Resolver.getLazyFunctionStubIfAvailable(F);
  • if (FnStub)
  • return FnStub;
  • else
  • return Resolver.getLazyFunctionStub(F);
  • }
  • }

JITEmitter.patch (972 Bytes)

Hi Dongpeng,

You probably want to post patches to the llvm-commits list rather than
llvmdev. That said:

I need to run c++ prgrams using lli. However, I find lli cannot handle the
alias instruction correctly. Following is an example:

The backtrace indicates you're using the old JIT, which we're trying
our hardest to get rid of completely. Its replacement is called MCJIT
and seems to support your code already (at least on my amd64 Linux):

$ lli -use-mcjit example.bc
constructor
destructor

Longer term, you almost certainly want to look into that. If MCJIT is
missing features you need, we'd like to know about it so that they can
be implemented.

Cheers.

Tim.

Thanks for your response, Tim!

I have posted the patch to the commits mailing list. I also tried to use mcjit however the error came out as:

LLVM ERROR: Program used external function ‘__dso_handle’ which could not be resolved!

Am I missing some libraries?

Thanks,
Dongpeng

LLVM ERROR: Program used external function '__dso_handle' which could not be
resolved!

Am I missing some libraries?

Apparently (llvm.org/bugs/show_bug.cgi?id=7847) that's related to how
libstdc++ gets initialized and the old JIT has a special hack for that
symbol. You can give clang the extra "-fno-use-cxa-atexit" option as a
work-around.

Cheers.

Tim.

Hey,

you might want to take a look at this bug report:
Bug 12666 – Hitting recursive JIT assert w/ aliases
  http://llvm.org/bugs/show_bug.cgi?id=12666

Best regards,
  Johannes