More Tao3D / XLR repair work

Thursday, July 20, 2017

This time, I think I won't give up. I must repair this code, I'm really annoyed not to be able to run Tao3D anymore except with completely outdated versions of LLVM.

Activating LLVM traces in the compiler, I see a function that looks perfectly normal:

define internal %Tree* @xl_eval(%1*, %Tree*) {
allocas:
  %result = alloca %Tree*
  store %Tree* %1, %Tree** %result
  %2 = load i32, i32* inttoptr (i64 4314967428 to i32*)
  %3 = add i32 %2, 1
  store i32 %3, i32* inttoptr (i64 4314967428 to i32*)
  %stackCheck = icmp ugt i32 %3, 1000
  br i1 %stackCheck, label %overflow, label %entry

entry: ; preds = %allocas br label %exit

exit: ; preds = %overflow, %entry %4 = load i32, i32* inttoptr (i64 4314967428 to i32*) %5 = sub i32 %4, 1 store i32 %5, i32* inttoptr (i64 4314967428 to i32*) %retval = load %Tree*, %Tree** %result ret %Tree* %retval

overflow: ; preds = %allocas %6 = load %Tree*, %Tree** %result %7 = call %Tree* @xl_stack_overflow(%Tree* %6) br label %exit }

Why would it crash on something that simple?

Found two things in the examples:

    (*module)->setDataLayout(runtime->getDataLayout());

and

     PM->doInitialization();

The latter got me confused because for some reason createXLFunctionPasses was taking a PassManagerBase instead of a FunctionPassManager, and that base does not have doInitialization.

When there are new things like this, it's very hard to know when they were officially introduced. git blame gives me some history, but that's it.

Now, at least, it does not crash. Now it fails at runtime with:

LLVM ERROR: Target does not support MC emission!

Whaaaat? The thing is called MCJIT, does that not stand for "Machine Code JIT"?

It looks like LLVMInitializeNativeTarget may be the problem. But it's interesting, the post talks about 3.50, and I needed that call at that time. Well, that does not work: the engineBuilder.create() call fails with Unable to find target for this triple (no targets are registered).

Finally figured out that the trick was to add:

 InitializeNativeTargetAsmPrinter();
 InitializeNativeTargetAsmParser();
 InitializeNativeTargetDisassembler();

But then, it generates machine code that looks correct, but won't execute. I get a EXC_BAD_ACCESS stepping into the first instruction of my disassembly:

    0x101dec000: pushq  %r14
    0x101dec002: pushq  %rbx
    0x101dec003: pushq  %rax
    0x101dec004: movq   %rsi, %rbx
    0x101dec007: movabsq $0x101576164, %r14        ; imm = 0x101576164
    0x101dec011: movl   (%r14), %eax
    0x101dec014: incl   %eax
    0x101dec016: movl   %eax, (%r14)
    0x101dec019: cmpl   $0x3e8, %eax              ; imm = 0x3E8
    0x101dec01e: jbe    0x101dec032

This is the code that increments the recursion stack count check. I cannot use the "Step instruction" si of the debugger on the first instruction. So apparently, I still need something else to tell LLVM that when it generate code, it would be neat to map it in a way that it can actually execute...

More Googling reveals that I apparently need to call finalizeObject on the execution engine. After that, I end up with a good old assert in unresolved_external for symbol xl_stack_overflow.

Added some symbol resolution in unresolved external. After that, the first function works, but the second call to getPointerToFunction returns 0. So that's still not good.

Tried to compile the tutorials, but they don't compile correctly with either LLVM 3.9 or 4.0. This is so crappy.

With clang++, I get:

% clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs ` -O3 -o toy
In file included from toy.cpp:1:
In file included from /usr/local/Cellar/llvm@3.9/3.9.1_1/include/llvm/ADT/STLExtras.h:20:
In file included from /usr/local/Cellar/llvm@3.9/3.9.1_1/bin/../include/c++/v1/algorithm:632:
In file included from /usr/local/Cellar/llvm@3.9/3.9.1_1/bin/../include/c++/v1/cstring:61:
/usr/local/Cellar/llvm@3.9/3.9.1_1/bin/../include/c++/v1/string.h:61:15: fatal error:
      'string.h' file not found
#include_next 
              ^
1 error generated.

Interesting, if I use g++ instead of clang++, then I get a different error:

g++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs ` -O3 -o toy
In file included from toy.cpp:17:
./../include/KaleidoscopeJIT.h:20:10: fatal error:
      'llvm/ExecutionEngine/JITSymbol.h' file not found
#include "llvm/ExecutionEngine/JITSymbol.h"
         ^
1 error generated.

If I switch to the more modern LLVM 4.0, then I get:

g++ -g toy.cpp `/usr/local/opt/llvm@4/bin/llvm-config --cxxflags --ldflags --system-libs --libs ` -O3 -o toy
In file included from toy.cpp:17:
./../include/KaleidoscopeJIT.h:26:10: fatal error:
      'llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h' file not found
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
         ^
1 error generated.

The missing RTDyldObjectLinkingLayer.h is precisely the part that I am having trouble with right now.

Looking at this blog, it looks like it's now necessary to create a new module each time a function has been JIT'ed.