[LLVMdev] Assertion failure in MC emitter running LLVM libs on Android using android-ndk

Peter Zion peter.zion at fabric-engine.com
Tue May 31 16:36:17 PDT 2011


Hello,

I am encountering a strange assertion failure using the LLVM libraries cross-compiled for Android using the Android NDK.  I am using the official release of LLVM-2.9.

The IR which is causing the assertion failure is the following:

define void @__construct_Byte__Integer(i8* nocapture %byteLValue, i32 %integerRValue) inlinehint {
entry:
  %0 = trunc i32 %integerRValue to i8
  store i8 %0, i8* %byteLValue
  ret void
}

define void @entry() inlinehint {
entry:
  %castToByte = alloca i8
  call void @__construct_Byte__Integer(i8* %castToByte, i32 16)
  %0 = load i8* %castToByte
  ret void
}

And the assertion failure is the following:

assertion "isReg() && "This is not a register operand!"" failed: file "/Users/pzion/Fabric/ThirdParty/Build/Android/arm/llvm-2.9/include/llvm/CodeGen/MachineOperand.h", line 202, function "unsigned int llvm::MachineOperand::getReg() const"
Stack dump:
0.	Running pass 'ARM Machine Code Emitter' on function '@__construct_Byte__Integer'

The library is running on the Android device which has a cortex-9 CPU.  The library usage to generate the machine code is:

        std::string errStr;
        llvm::EngineBuilder builder( module.get() );
        
        builder.setErrorStr( &errStr );
        builder.setEngineKind( llvm::EngineKind::JIT );

        std::auto_ptr<llvm::ExecutionEngine> executionEngine( builder.create() );

        llvm::Function *llvmEntry = module->getFunction( "entry" );
        void (*entryPtr)() = (void (*)())executionEngine->getPointerToFunction( llvmEntry );

What is so strange about this error is that if I instead output the ARM assembly language then assembly it on the build host using the Android NDK toolchain, it assembles without any problem at all.  The library usage to generate the assembly is:

        std::string   errorStr;
        std::string   targetTriple = llvm::sys::getHostTriple();
        const llvm::Target *target = llvm::TargetRegistry::lookupTarget( targetTriple, errorStr );

        llvm::TargetMachine *targetMachine = target->createTargetMachine( targetTriple, "" );
        targetMachine->setAsmVerbosityDefault( true );

        llvm::FunctionPassManager *functionPassManager = new llvm::FunctionPassManager( module.get() );
        targetMachine->addPassesToEmitFile( 
          *functionPassManager, llvm::fouts(), 
          llvm::TargetMachine::CGFT_AssemblyFile, optLevel );
        functionPassManager->doInitialization();
        llvm::Module::FunctionListType &functionList = module->getFunctionList();
        for ( llvm::Module::FunctionListType::iterator it=functionList.begin(); it!=functionList.end(); ++it )
          functionPassManager->run( *it );
        delete functionPassManager;

It seems very bizarre to me that the back end can generate the assembly code but can't generate the machine code directly.

Note that I have been unable to get the command-line tools (eg. llc) to cross-compile to Android, but I don't actually need them for my project; I use the LLVM libraries directly.  Note also that I'm explicitly replacing the cross-compiled tblgen with one compiled (from the same version of LLVM) for the build machine (x86_64-darwin-10) in order to make the compile work; but from what I understand the tblgen output is platform independent anyway.

Can anyone offer me any clues as to what might be going wrong here?  Explicitly specifying -march=arm and/or -mcpu=cortex-9 to the EngineBuilder makes no difference.

Thanks in advance,
Peter Zion






More information about the llvm-dev mailing list