ARM opcode format

I’m doing some tests running llvm on Android. I’m getting an error message saying:

Unhandled instruction encoding format!

I checked which instruction was causing this and it is ADDrsi, it appears to have format 42 << 7, which is definitely not available in ARMBaseInfo.h

Any suggestions are welcome

Hi Guillermo,

It’s difficult to do anything without a testcase – do you have a (reduced) testcase available?

Cheers,

James

Hi,

I haven’t been able to reproduce this problem on a smaller test and the original source code is from another virtual machine’s IR. What I found out was that 42 << 7 is actually DPSoRegImmFrm, defined in ARMInstrFormats.td. This format is not dealt with in the ARMCodeEmitter.cpp and that’s the problem I’m facing.

The triple I’m using is “armv7-unknown-linux-gnueabi” and the bitcode I’m dealing with is:

; ModuleID = ‘CRYO jit’
target triple = “armv7a-unknown-linux-gnueabi”
define i32 @execute(i8* %JNIEnv, i8* %v8) {
entry:
%litTemp = alloca i32
%v0_INTEGER = alloca i32
%v4_INTEGER = alloca i32
%v5_INTEGER = alloca i32
%v2_INTEGER = alloca i32
%v6_INTEGER = alloca i32
%v5_POINTER = alloca i8*
%v1_INTEGER = alloca i32
%v3_INTEGER = alloca i32
%v7_INTEGER = alloca i32
store i32 1, i32* %v7_INTEGER
store i32 1, i32* %v3_INTEGER
store i32 0, i32* %v1_INTEGER
%0 = getelementptr i8* %v8, i32 8
%1 = bitcast i8* %0 to i8**
%2 = load i8** %1
store i8* %2, i8** %v5_POINTER
store i32 0, i32* %v6_INTEGER
%3 = load i8** %v5_POINTER
%4 = getelementptr i8* %3, i32 12
%5 = bitcast i8* %4 to i32*
%6 = load i32* %v6_INTEGER
%7 = getelementptr i32* %5, i32 %6
%8 = load i32* %v7_INTEGER
store i32 %8, i32* %7
%9 = getelementptr i8* %v8, i32 8
%10 = bitcast i8* %9 to i8**
%11 = load i8** %10
store i8* %11, i8** %v5_POINTER
store i32 2, i32* %v6_INTEGER
%12 = load i8** %v5_POINTER
%13 = getelementptr i8* %12, i32 12
%14 = bitcast i8* %13 to i32*
%15 = load i32* %v7_INTEGER
%16 = getelementptr i32* %14, i32 %15
%17 = load i32* %v6_INTEGER
store i32 %17, i32* %16
store i32 2, i32* %v3_INTEGER
store i32 3, i32* %v2_INTEGER
br label %label000f
label000f: ; preds = %merge0024, %entry
%18 = getelementptr i8* %v8, i32 12
%19 = bitcast i8* %18 to i32*
%20 = load i32* %19
store i32 %20, i32* %v5_INTEGER
%21 = load i32* %v2_INTEGER
%22 = load i32* %v5_INTEGER
%23 = icmp slt i32 %21, %22
br i1 %23, label %merge0014, label %else
else: ; preds = %label000f
%24 = load i32* %v3_INTEGER
ret i32 %24
merge0014: ; preds = %label000f
store i32 1, i32* %v4_INTEGER
store i32 1, i32* %v0_INTEGER
br label %label0016
label0016: ; preds = %merge003e, %merge0014
%25 = load i32* %v4_INTEGER
%26 = load i32* %v3_INTEGER
%27 = icmp sge i32 %25, %26
br i1 %27, label %merge001a, label %else1
else1: ; preds = %label0016
%28 = load i32* %v0_INTEGER
%29 = icmp ne i32 %28, 0
br i1 %29, label %merge0027, label %else2
else2: ; preds = %else1
br label %merge001a
merge001a: ; preds = %else2, %label0016
%30 = load i32* %v0_INTEGER
%31 = icmp eq i32 %30, 0
br i1 %31, label %merge0024, label %else3
else3: ; preds = %merge001a
%32 = load i32* %v3_INTEGER
store i32 1, i32* %litTemp
%33 = load i32* %litTemp
%34 = add i32 %32, %33
store i32 %34, i32* %v3_INTEGER
%35 = getelementptr i8* %v8, i32 8
%36 = bitcast i8* %35 to i8**
%37 = load i8** %36
store i8* %37, i8** %v5_POINTER
%38 = load i32* %v3_INTEGER
%39 = load i32* %v7_INTEGER
%40 = sub i32 %38, %39
store i32 %40, i32* %v6_INTEGER
%41 = load i8** %v5_POINTER
%42 = getelementptr i8* %41, i32 12
%43 = bitcast i8* %42 to i32*
%44 = load i32* %v6_INTEGER
%45 = getelementptr i32* %43, i32 %44
%46 = load i32* %v2_INTEGER
store i32 %46, i32* %45
br label %merge0024
merge0024: ; preds = %else3, %merge001a
%47 = load i32* %v2_INTEGER
store i32 1, i32* %litTemp
%48 = load i32* %litTemp
%49 = add i32 %47, %48
store i32 %49, i32* %v2_INTEGER
br label %label000f
merge0027: ; preds = %else1
%50 = getelementptr i8* %v8, i32 8
%51 = bitcast i8* %50 to i8**
%52 = load i8** %51
store i8* %52, i8** %v5_POINTER
%53 = load i8** %v5_POINTER
%54 = getelementptr i8* %53, i32 12
%55 = bitcast i8* %54 to i32*
%56 = load i32* %v4_INTEGER
%57 = getelementptr i32* %55, i32 %56
%58 = load i32* %57
store i32 %58, i32* %v5_INTEGER
%59 = load i32* %v5_INTEGER
%60 = icmp sle i32 %59, 0
br i1 %60, label %merge003e, label %else4
else4: ; preds = %merge0027
%61 = getelementptr i8* %v8, i32 8
%62 = bitcast i8* %61 to i8**
%63 = load i8** %62
store i8* %63, i8** %v5_POINTER
%64 = load i8** %v5_POINTER
%65 = getelementptr i8* %64, i32 12
%66 = bitcast i8* %65 to i32*
%67 = load i32* %v4_INTEGER
%68 = getelementptr i32* %66, i32 %67
%69 = load i32* %68
store i32 %69, i32* %v5_INTEGER
%70 = load i32* %v2_INTEGER
store i32 2, i32* %litTemp
%71 = load i32* %litTemp
%72 = udiv i32 %70, %71
store i32 %72, i32* %v6_INTEGER
%73 = load i32* %v5_INTEGER
%74 = load i32* %v6_INTEGER
%75 = icmp sgt i32 %73, %74
br i1 %75, label %merge003e, label %else5
else5: ; preds = %else4
%76 = getelementptr i8* %v8, i32 8
%77 = bitcast i8* %76 to i8**
%78 = load i8** %77
store i8* %78, i8** %v5_POINTER
%79 = load i8** %v5_POINTER
%80 = getelementptr i8* %79, i32 12
%81 = bitcast i8* %80 to i32*
%82 = load i32* %v4_INTEGER
%83 = getelementptr i32* %81, i32 %82
%84 = load i32* %83
store i32 %84, i32* %v5_INTEGER
%85 = load i32* %v2_INTEGER
%86 = load i32* %v5_INTEGER
%87 = urem i32 %85, %86
store i32 %87, i32* %v5_INTEGER
%88 = load i32* %v5_INTEGER
%89 = icmp ne i32 %88, 0
br i1 %89, label %merge003e, label %else6
else6: ; preds = %else5
store i32 0, i32* %v0_INTEGER
br label %merge003e
merge003e: ; preds = %else6, %else5, %else4, %merge0027
%90 = load i32* %v4_INTEGER
store i32 1, i32* %litTemp
%91 = load i32* %litTemp
%92 = add i32 %90, %91
store i32 %92, i32* %v4_INTEGER
br label %label0016
}

Thanks for your help,

Hi Guillermo,

I’m unable to reproduce the error you’re seeing with your bitcode input. “llc –mtriple armv7a-unknown-linux-gnueabi –O3” succeeds.

What are you using to reproduce, and what version?

Cheers,

James

Hi,

I’m sorry I forgot to mention I am compiling the bitcode using the JIT. The actual error, I get when I’m trying to get the function to the pointer. I’m using a custom front end that translates Android’s Dalvik bytecode into LLVM bitcode based on Android ICS’s modified LLVM version.

Thanks,

Guillermo,

Didn’t ICS ship with 2.9? You’d need to reproduce with trunk for this to be a valid bug report because it may be fixed already.

Cheers,

James

Guillermo,

I'm sorry I forgot to mention I am compiling the bitcode using the JIT. The
actual error, I get when I'm trying to get the function to the pointer. I'm
using a custom front end that translates Android's Dalvik bytecode into LLVM
bitcode based on Android ICS's modified LLVM version.

ARM JIT is broken in many ways. So, what you're seeing is perfectly
expected. You might want to wait until MCJIT will be usable and/or
provide patches to make this happen sooner :slight_smile:

Hello,

So the current JIT will be superseded by the MCJIT completely and no further development should be expected for the current JIT? In any case, I am definitely interested in submitting a patch if you could help me by sending me in the right direction, since I really want this working.

I managed to reproduce this behavior in LLVM 3.0 by modifying llc to read my .bc file and try to JIT the code for the mentioned Triple.

The error:

ARMCodeEmitter::emitPseudoInstruction
UNREACHABLE executed at /home/guillermo/llvm-3.0.src/lib/Target/ARM/ARMCodeEmitter.cpp:838!
Stack dump:
0. Program arguments: ./bin/llc -mtriple armv7a-unknown-linux-gnueabi -O3 /home/guillermo/Code/SieveAtom_execute.bc

  1. Running pass ‘ARM Machine Code Emitter’ on function ‘@execute
    Aborted (core dumped)

The code I modified for llc was:

//===-- llc.cpp - Implement the LLVM Native Code Generator ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the llc code generator driver. It provides a convenient
// command-line interface for generating native assembly-language code
// or C code, given LLVM bitcode.
//
//===----------------------------------------------------------------------===//
#include
#include “llvm/LLVMContext.h”
#include “llvm/Module.h”
#include “llvm/PassManager.h”
#include “llvm/Pass.h”
#include “llvm/ADT/Triple.h”
#include “llvm/Support/IRReader.h”
#include “llvm/CodeGen/LinkAllAsmWriterComponents.h”
#include “llvm/CodeGen/LinkAllCodegenComponents.h”
#include “llvm/Config/config.h”
#include “llvm/MC/SubtargetFeature.h”
#include “llvm/Support/CommandLine.h”
#include “llvm/Support/Debug.h”
#include “llvm/Support/FormattedStream.h”
#include “llvm/Support/ManagedStatic.h”
#include “llvm/Support/PluginLoader.h”
#include “llvm/Support/PrettyStackTrace.h”
#include “llvm/Support/ToolOutputFile.h”
#include “llvm/Support/Host.h”
#include “llvm/Support/Signals.h”
#include “llvm/Support/TargetRegistry.h”
#include “llvm/Support/TargetSelect.h”
#include “llvm/Target/TargetData.h”
#include “llvm/Target/TargetMachine.h”
#include “llvm/ExecutionEngine/ExecutionEngine.h”
#include “llvm/ExecutionEngine/JIT.h”
#include “llvm/Analysis/Passes.h”
#include “llvm/Transforms/Scalar.h”
#include
using namespace llvm;



// Build up all of the passes that we want to do to the module.
// PassManager PM;

// Add the target data from the target machine, if it exists, or the module.
//if (const TargetData *TD = Target.getTargetData())
// PM.add(new TargetData(*TD));
//else
// PM.add(new TargetData(&mod));

// Override default to generate verbose assembly.
//Target.setAsmVerbosityDefault(true);

//if (RelaxAll) {
// if (FileType != TargetMachine::CGFT_ObjectFile)
// errs() << argv[0]
// << “: warning: ignoring -mc-relax-all because filetype != obj”;
// else
// Target.setMCRelaxAll(true);
//}

//{
// formatted_raw_ostream FOS(Out->os());

// Ask the target to add backend passes as necessary.
// if (Target.addPassesToEmitFile(PM, FOS, FileType, OLvl, NoVerify)) {
// errs() << argv[0] << “: target does not support generation of this”
// << " file type!\n";
// return 1;
// }

// Before executing passes, print the final values of the LLVM options.
// cl::PrintOptionValues();

// PM.run(mod);
//}

// Declare success.
//Out->keep();

// mods for cryo
// create an execution engine to export code later
EngineBuilder eBuilder(&mod);
std::string error;
eBuilder.setErrorStr(&error);
ExecutionEngine *TheExecutionEngine = eBuilder.create();
if(!TheExecutionEngine) {
std::cout<<error.c_str()<<std::endl;
return 1;
}

// compile and return function pointer
FunctionPassManager OurFPM(&mod);
// Start with registering info about how the
// target lays out data structures.
OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData()));
// Provide basic AliasAnalysis support for GVN.
OurFPM.add(createBasicAliasAnalysisPass());
// Do simple “peephole” optimizations and bit-twiddling optzns.
OurFPM.add(createInstructionCombiningPass());
// Reassociate expressions.
OurFPM.add(createReassociatePass());
// Eliminate Common SubExpressions.
OurFPM.add(createGVNPass());
// Simplify the control flow graph (deleting unreachable blocks, etc).
OurFPM.add(createCFGSimplificationPass());

// we run optimizations and return the pointer to the function
OurFPM.doInitialization();
Function* currentF = mod.getFunction(“execute”);
OurFPM.run(*currentF);

TheExecutionEngine->getPointerToFunction(currentF);

return 0;
}

Thanks again for your help,

Hello,

So the current JIT will be superseded by the MCJIT completely and no further development should be expected for the current JIT?

Yes.