Foundation for Quick LLVM compiler
Ready for review - probably better get this cleaned up and
checked in even though much work remains.
Basic conversion from MIR to GreenlandIR and from GreenlandIR
back to LIR. Support sufficient to run Fibonacci test.
Note some structural changes in MIR to support this work:
o retaining incoming label for phi nodes
o constant propagation
o include object reference detection in type inference pass
Change-Id: I8ba63c73e76d071aa40cae0f744e598b96f68699
diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/CompilerCodegen.h
index 9381735..4508416 100644
--- a/src/compiler/codegen/CompilerCodegen.h
+++ b/src/compiler/codegen/CompilerCodegen.h
@@ -35,6 +35,10 @@
/* Lower middle-level IR to low-level IR for the whole method */
void oatMethodMIR2LIR(CompilationUnit* cUnit);
+/* Bitcode conversions */
+void oatMethodMIR2Bitcode(CompilationUnit* cUnit);
+void oatMethodBitcode2LIR(CompilationUnit* cUnit);
+
/* Lower middle-level IR to low-level IR for the simple methods */
void oatSpecialMIR2LIR(CompilationUnit* cUnit, SpecialCaseHandler specialCase );
diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc
new file mode 100644
index 0000000..27e7d26
--- /dev/null
+++ b/src/compiler/codegen/MethodBitcode.cc
@@ -0,0 +1,1674 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(ART_USE_QUICK_COMPILER)
+
+#include "object_utils.h"
+
+#include <llvm/Support/ToolOutputFile.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/Metadata.h>
+#include <llvm/ADT/DepthFirstIterator.h>
+#include <llvm/Instruction.h>
+#include <llvm/Type.h>
+#include <llvm/Instructions.h>
+#include <llvm/Support/Casting.h>
+
+const char* labelFormat = "L0x%x_d";
+
+namespace art {
+extern const RegLocation badLoc;
+
+llvm::BasicBlock* getLLVMBlock(CompilationUnit* cUnit, int id)
+{
+ return cUnit->idToBlockMap.Get(id);
+}
+
+llvm::Value* getLLVMValue(CompilationUnit* cUnit, int sReg)
+{
+ return (llvm::Value*)oatGrowableListGetElement(&cUnit->llvmValues, sReg);
+}
+
+// Replace the placeholder value with the real definition
+void defineValue(CompilationUnit* cUnit, llvm::Value* val, int sReg)
+{
+ llvm::Value* placeholder = getLLVMValue(cUnit, sReg);
+ CHECK(placeholder != NULL) << "Null placeholder - shouldn't happen";
+ placeholder->replaceAllUsesWith(val);
+ val->takeName(placeholder);
+ cUnit->llvmValues.elemList[sReg] = (intptr_t)val;
+}
+
+llvm::Type* llvmTypeFromLocRec(CompilationUnit* cUnit, RegLocation loc)
+{
+ llvm::Type* res = NULL;
+ if (loc.wide) {
+ if (loc.fp)
+ res = cUnit->irb->GetJDoubleTy();
+ else
+ res = cUnit->irb->GetJLongTy();
+ } else {
+ if (loc.fp) {
+ res = cUnit->irb->GetJFloatTy();
+ } else {
+ if (loc.ref)
+ res = cUnit->irb->GetJObjectTy();
+ else
+ res = cUnit->irb->GetJIntTy();
+ }
+ }
+ return res;
+}
+
+void initIR(CompilationUnit* cUnit)
+{
+ cUnit->context = new llvm::LLVMContext();
+ cUnit->module = new llvm::Module("art", *cUnit->context);
+ llvm::StructType::create(*cUnit->context, "JavaObject");
+ llvm::StructType::create(*cUnit->context, "Method");
+ llvm::StructType::create(*cUnit->context, "Thread");
+ cUnit->intrinsic_helper =
+ new greenland::IntrinsicHelper(*cUnit->context, *cUnit->module);
+ cUnit->irb =
+ new greenland::IRBuilder(*cUnit->context, *cUnit->module,
+ *cUnit->intrinsic_helper);
+}
+
+void freeIR(CompilationUnit* cUnit)
+{
+ delete cUnit->irb;
+ delete cUnit->intrinsic_helper;
+ delete cUnit->module;
+ delete cUnit->context;
+}
+
+const char* llvmSSAName(CompilationUnit* cUnit, int ssaReg) {
+ return GET_ELEM_N(cUnit->ssaStrings, char*, ssaReg);
+}
+
+llvm::Value* emitConst(CompilationUnit* cUnit, llvm::ArrayRef<llvm::Value*> src,
+ RegLocation loc)
+{
+ greenland::IntrinsicHelper::IntrinsicId id;
+ if (loc.wide) {
+ if (loc.fp) {
+ id = greenland::IntrinsicHelper::ConstDouble;
+ } else {
+ id = greenland::IntrinsicHelper::ConstLong;
+ }
+ } else {
+ if (loc.fp) {
+ id = greenland::IntrinsicHelper::ConstFloat;
+ } if (loc.ref) {
+ id = greenland::IntrinsicHelper::ConstObj;
+ } else {
+ id = greenland::IntrinsicHelper::ConstInt;
+ }
+ }
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ return cUnit->irb->CreateCall(intr, src);
+}
+llvm::Value* emitCopy(CompilationUnit* cUnit, llvm::ArrayRef<llvm::Value*> src,
+ RegLocation loc)
+{
+ greenland::IntrinsicHelper::IntrinsicId id;
+ if (loc.wide) {
+ if (loc.fp) {
+ id = greenland::IntrinsicHelper::CopyDouble;
+ } else {
+ id = greenland::IntrinsicHelper::CopyLong;
+ }
+ } else {
+ if (loc.fp) {
+ id = greenland::IntrinsicHelper::CopyFloat;
+ } if (loc.ref) {
+ id = greenland::IntrinsicHelper::CopyObj;
+ } else {
+ id = greenland::IntrinsicHelper::CopyInt;
+ }
+ }
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ return cUnit->irb->CreateCall(intr, src);
+}
+
+void emitSuspendCheck(CompilationUnit* cUnit)
+{
+ greenland::IntrinsicHelper::IntrinsicId id =
+ greenland::IntrinsicHelper::CheckSuspend;
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ cUnit->irb->CreateCall(intr);
+}
+
+llvm::Value* convertCompare(CompilationUnit* cUnit, ConditionCode cc,
+ llvm::Value* src1, llvm::Value* src2)
+{
+ llvm::Value* res = NULL;
+ switch(cc) {
+ case kCondEq: res = cUnit->irb->CreateICmpEQ(src1, src2); break;
+ case kCondNe: res = cUnit->irb->CreateICmpNE(src1, src2); break;
+ case kCondLt: res = cUnit->irb->CreateICmpSLT(src1, src2); break;
+ case kCondGe: res = cUnit->irb->CreateICmpSGE(src1, src2); break;
+ case kCondGt: res = cUnit->irb->CreateICmpSGT(src1, src2); break;
+ case kCondLe: res = cUnit->irb->CreateICmpSLE(src1, src2); break;
+ default: LOG(FATAL) << "Unexpected cc value " << cc;
+ }
+ return res;
+}
+
+void convertCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
+ ConditionCode cc, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ if (bb->taken->startOffset <= mir->offset) {
+ emitSuspendCheck(cUnit);
+ }
+ llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg);
+ llvm::Value* src2 = getLLVMValue(cUnit, rlSrc2.origSReg);
+ llvm::Value* condValue = convertCompare(cUnit, cc, src1, src2);
+ condValue->setName(StringPrintf("t%d", cUnit->tempName++));
+ cUnit->irb->CreateCondBr(condValue, getLLVMBlock(cUnit, bb->taken->id),
+ getLLVMBlock(cUnit, bb->fallThrough->id));
+}
+
+void convertCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
+ MIR* mir, ConditionCode cc, RegLocation rlSrc1)
+{
+ if (bb->taken->startOffset <= mir->offset) {
+ emitSuspendCheck(cUnit);
+ }
+ llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg);
+ llvm::Value* src2;
+ if (rlSrc1.ref) {
+ src2 = cUnit->irb->GetJNull();
+ } else {
+ src2 = cUnit->irb->getInt32(0);
+ }
+ llvm::Value* condValue = convertCompare(cUnit, cc, src1, src2);
+ condValue->setName(StringPrintf("t%d", cUnit->tempName++));
+ cUnit->irb->CreateCondBr(condValue, getLLVMBlock(cUnit, bb->taken->id),
+ getLLVMBlock(cUnit, bb->fallThrough->id));
+}
+
+llvm::Value* genDivModOp(CompilationUnit* cUnit, bool isDiv, bool isLong,
+ llvm::Value* src1, llvm::Value* src2)
+{
+ greenland::IntrinsicHelper::IntrinsicId id;
+ if (isLong) {
+ if (isDiv) {
+ id = greenland::IntrinsicHelper::DivLong;
+ } else {
+ id = greenland::IntrinsicHelper::RemLong;
+ }
+ } else if (isDiv) {
+ id = greenland::IntrinsicHelper::DivInt;
+ } else {
+ id = greenland::IntrinsicHelper::RemInt;
+ }
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ llvm::SmallVector<llvm::Value*, 2>args;
+ args.push_back(src1);
+ args.push_back(src2);
+ return cUnit->irb->CreateCall(intr, args);
+}
+
+llvm::Value* genArithOp(CompilationUnit* cUnit, OpKind op, bool isLong,
+ llvm::Value* src1, llvm::Value* src2)
+{
+ llvm::Value* res = NULL;
+ switch(op) {
+ case kOpAdd: res = cUnit->irb->CreateAdd(src1, src2); break;
+ case kOpSub: res = cUnit->irb->CreateSub(src1, src2); break;
+ case kOpMul: res = cUnit->irb->CreateMul(src1, src2); break;
+ case kOpOr: res = cUnit->irb->CreateOr(src1, src2); break;
+ case kOpAnd: res = cUnit->irb->CreateAnd(src1, src2); break;
+ case kOpXor: res = cUnit->irb->CreateXor(src1, src2); break;
+ case kOpDiv: res = genDivModOp(cUnit, true, isLong, src1, src2); break;
+ case kOpRem: res = genDivModOp(cUnit, false, isLong, src1, src2); break;
+ case kOpLsl: UNIMPLEMENTED(FATAL) << "Need Lsl"; break;
+ case kOpLsr: UNIMPLEMENTED(FATAL) << "Need Lsr"; break;
+ case kOpAsr: UNIMPLEMENTED(FATAL) << "Need Asr"; break;
+ default:
+ LOG(FATAL) << "Invalid op " << op;
+ }
+ return res;
+}
+
+void convertFPArithOp(CompilationUnit* cUnit, OpKind op, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg);
+ llvm::Value* src2 = getLLVMValue(cUnit, rlSrc2.origSReg);
+ llvm::Value* res = NULL;
+ switch(op) {
+ case kOpAdd: res = cUnit->irb->CreateFAdd(src1, src2); break;
+ case kOpSub: res = cUnit->irb->CreateFSub(src1, src2); break;
+ case kOpMul: res = cUnit->irb->CreateFMul(src1, src2); break;
+ case kOpDiv: res = cUnit->irb->CreateFDiv(src1, src2); break;
+ case kOpRem: res = cUnit->irb->CreateFRem(src1, src2); break;
+ default:
+ LOG(FATAL) << "Invalid op " << op;
+ }
+ defineValue(cUnit, res, rlDest.origSReg);
+}
+
+void convertArithOp(CompilationUnit* cUnit, OpKind op, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg);
+ llvm::Value* src2 = getLLVMValue(cUnit, rlSrc2.origSReg);
+ llvm::Value* res = genArithOp(cUnit, op, rlDest.wide, src1, src2);
+ defineValue(cUnit, res, rlDest.origSReg);
+}
+
+void convertArithOpLit(CompilationUnit* cUnit, OpKind op, RegLocation rlDest,
+ RegLocation rlSrc1, int32_t imm)
+{
+ llvm::Value* src1 = getLLVMValue(cUnit, rlSrc1.origSReg);
+ llvm::Value* src2 = cUnit->irb->getInt32(imm);
+ llvm::Value* res = genArithOp(cUnit, op, rlDest.wide, src1, src2);
+ defineValue(cUnit, res, rlDest.origSReg);
+}
+
+/*
+ * Target-independent code generation. Use only high-level
+ * load/store utilities here, or target-dependent genXX() handlers
+ * when necessary.
+ */
+bool convertMIRNode(CompilationUnit* cUnit, MIR* mir, BasicBlock* bb,
+ llvm::BasicBlock* llvmBB, LIR* labelList)
+{
+ bool res = false; // Assume success
+ RegLocation rlSrc[3];
+ RegLocation rlDest = badLoc;
+ RegLocation rlResult = badLoc;
+ Instruction::Code opcode = mir->dalvikInsn.opcode;
+
+ /* Prep Src and Dest locations */
+ int nextSreg = 0;
+ int nextLoc = 0;
+ int attrs = oatDataFlowAttributes[opcode];
+ rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
+ if (attrs & DF_UA) {
+ if (attrs & DF_A_WIDE) {
+ rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg, nextSreg + 1);
+ nextSreg+= 2;
+ } else {
+ rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
+ nextSreg++;
+ }
+ }
+ if (attrs & DF_UB) {
+ if (attrs & DF_B_WIDE) {
+ rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg, nextSreg + 1);
+ nextSreg+= 2;
+ } else {
+ rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
+ nextSreg++;
+ }
+ }
+ if (attrs & DF_UC) {
+ if (attrs & DF_C_WIDE) {
+ rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg, nextSreg + 1);
+ } else {
+ rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
+ }
+ }
+ if (attrs & DF_DA) {
+ if (attrs & DF_A_WIDE) {
+ rlDest = oatGetDestWide(cUnit, mir, 0, 1);
+ } else {
+ rlDest = oatGetDest(cUnit, mir, 0);
+ }
+ }
+
+ switch (opcode) {
+ case Instruction::NOP:
+ break;
+
+ case Instruction::MOVE:
+ case Instruction::MOVE_OBJECT:
+ case Instruction::MOVE_16:
+ case Instruction::MOVE_OBJECT_16:
+ case Instruction::MOVE_FROM16:
+ case Instruction::MOVE_WIDE:
+ case Instruction::MOVE_WIDE_16:
+ case Instruction::MOVE_WIDE_FROM16: {
+ /*
+ * Moves/copies are meaningless in pure SSA register form,
+ * but we need to preserve them for the conversion back into
+ * MIR (at least until we stop using the Dalvik register maps).
+ * Insert a dummy intrinsic copy call, which will be recognized
+ * by the quick path and removed by the portable path.
+ */
+ llvm::Value* src = getLLVMValue(cUnit, rlSrc[0].origSReg);
+ llvm::Value* res = emitCopy(cUnit, src, rlDest);
+ defineValue(cUnit, res, rlDest.origSReg);
+ }
+ break;
+
+ case Instruction::CONST:
+ case Instruction::CONST_4:
+ case Instruction::CONST_16: {
+ llvm::Constant* immValue = cUnit->irb->GetJInt(mir->dalvikInsn.vB);
+ llvm::Value* res = emitConst(cUnit, immValue, rlDest);
+ defineValue(cUnit, res, rlDest.origSReg);
+ }
+ break;
+
+ case Instruction::CONST_WIDE_16:
+ case Instruction::CONST_WIDE_32: {
+ llvm::Constant* immValue = cUnit->irb->GetJLong(mir->dalvikInsn.vB);
+ llvm::Value* res = emitConst(cUnit, immValue, rlDest);
+ defineValue(cUnit, res, rlDest.origSReg);
+ }
+ break;
+
+ case Instruction::CONST_HIGH16: {
+ llvm::Constant* immValue = cUnit->irb->GetJInt(mir->dalvikInsn.vB << 16);
+ llvm::Value* res = emitConst(cUnit, immValue, rlDest);
+ defineValue(cUnit, res, rlDest.origSReg);
+ }
+ break;
+
+ case Instruction::CONST_WIDE: {
+ llvm::Constant* immValue =
+ cUnit->irb->GetJLong(mir->dalvikInsn.vB_wide);
+ llvm::Value* res = emitConst(cUnit, immValue, rlDest);
+ defineValue(cUnit, res, rlDest.origSReg);
+ }
+ case Instruction::CONST_WIDE_HIGH16: {
+ int64_t imm = static_cast<int64_t>(mir->dalvikInsn.vB) << 48;
+ llvm::Constant* immValue = cUnit->irb->GetJLong(imm);
+ llvm::Value* res = emitConst(cUnit, immValue, rlDest);
+ defineValue(cUnit, res, rlDest.origSReg);
+ }
+
+ case Instruction::RETURN_WIDE:
+ case Instruction::RETURN:
+ case Instruction::RETURN_OBJECT: {
+ if (!cUnit->attrs & METHOD_IS_LEAF) {
+ emitSuspendCheck(cUnit);
+ }
+ cUnit->irb->CreateRet(getLLVMValue(cUnit, rlSrc[0].origSReg));
+ bb->hasReturn = true;
+ }
+ break;
+
+ case Instruction::RETURN_VOID: {
+ if (!cUnit->attrs & METHOD_IS_LEAF) {
+ emitSuspendCheck(cUnit);
+ }
+ cUnit->irb->CreateRetVoid();
+ bb->hasReturn = true;
+ }
+ break;
+
+ case Instruction::IF_EQ:
+ convertCompareAndBranch(cUnit, bb, mir, kCondEq, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::IF_NE:
+ convertCompareAndBranch(cUnit, bb, mir, kCondNe, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::IF_LT:
+ convertCompareAndBranch(cUnit, bb, mir, kCondLt, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::IF_GE:
+ convertCompareAndBranch(cUnit, bb, mir, kCondGe, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::IF_GT:
+ convertCompareAndBranch(cUnit, bb, mir, kCondGt, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::IF_LE:
+ convertCompareAndBranch(cUnit, bb, mir, kCondLe, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::IF_EQZ:
+ convertCompareZeroAndBranch(cUnit, bb, mir, kCondEq, rlSrc[0]);
+ break;
+ case Instruction::IF_NEZ:
+ convertCompareZeroAndBranch(cUnit, bb, mir, kCondNe, rlSrc[0]);
+ break;
+ case Instruction::IF_LTZ:
+ convertCompareZeroAndBranch(cUnit, bb, mir, kCondLt, rlSrc[0]);
+ break;
+ case Instruction::IF_GEZ:
+ convertCompareZeroAndBranch(cUnit, bb, mir, kCondGe, rlSrc[0]);
+ break;
+ case Instruction::IF_GTZ:
+ convertCompareZeroAndBranch(cUnit, bb, mir, kCondGt, rlSrc[0]);
+ break;
+ case Instruction::IF_LEZ:
+ convertCompareZeroAndBranch(cUnit, bb, mir, kCondLe, rlSrc[0]);
+ break;
+
+ case Instruction::GOTO:
+ case Instruction::GOTO_16:
+ case Instruction::GOTO_32: {
+ if (bb->taken->startOffset <= bb->startOffset) {
+ emitSuspendCheck(cUnit);
+ }
+ cUnit->irb->CreateBr(getLLVMBlock(cUnit, bb->taken->id));
+ }
+ break;
+
+ case Instruction::ADD_LONG:
+ case Instruction::ADD_LONG_2ADDR:
+ case Instruction::ADD_INT:
+ case Instruction::ADD_INT_2ADDR:
+ convertArithOp(cUnit, kOpAdd, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::SUB_LONG:
+ case Instruction::SUB_LONG_2ADDR:
+ case Instruction::SUB_INT:
+ case Instruction::SUB_INT_2ADDR:
+ convertArithOp(cUnit, kOpSub, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::MUL_LONG:
+ case Instruction::MUL_LONG_2ADDR:
+ case Instruction::MUL_INT:
+ case Instruction::MUL_INT_2ADDR:
+ convertArithOp(cUnit, kOpMul, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::DIV_LONG:
+ case Instruction::DIV_LONG_2ADDR:
+ case Instruction::DIV_INT:
+ case Instruction::DIV_INT_2ADDR:
+ convertArithOp(cUnit, kOpDiv, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::REM_LONG:
+ case Instruction::REM_LONG_2ADDR:
+ case Instruction::REM_INT:
+ case Instruction::REM_INT_2ADDR:
+ convertArithOp(cUnit, kOpRem, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::AND_LONG:
+ case Instruction::AND_LONG_2ADDR:
+ case Instruction::AND_INT:
+ case Instruction::AND_INT_2ADDR:
+ convertArithOp(cUnit, kOpAnd, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::OR_LONG:
+ case Instruction::OR_LONG_2ADDR:
+ case Instruction::OR_INT:
+ case Instruction::OR_INT_2ADDR:
+ convertArithOp(cUnit, kOpOr, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::XOR_LONG:
+ case Instruction::XOR_LONG_2ADDR:
+ case Instruction::XOR_INT:
+ case Instruction::XOR_INT_2ADDR:
+ convertArithOp(cUnit, kOpXor, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::SHL_LONG:
+ case Instruction::SHL_LONG_2ADDR:
+ case Instruction::SHL_INT:
+ case Instruction::SHL_INT_2ADDR:
+ convertArithOp(cUnit, kOpLsl, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::SHR_LONG:
+ case Instruction::SHR_LONG_2ADDR:
+ case Instruction::SHR_INT:
+ case Instruction::SHR_INT_2ADDR:
+ convertArithOp(cUnit, kOpAsr, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+ case Instruction::USHR_LONG:
+ case Instruction::USHR_LONG_2ADDR:
+ case Instruction::USHR_INT:
+ case Instruction::USHR_INT_2ADDR:
+ convertArithOp(cUnit, kOpLsr, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+
+ case Instruction::ADD_INT_LIT16:
+ case Instruction::ADD_INT_LIT8:
+ convertArithOpLit(cUnit, kOpAdd, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::RSUB_INT:
+ case Instruction::RSUB_INT_LIT8:
+ convertArithOpLit(cUnit, kOpRsub, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::MUL_INT_LIT16:
+ case Instruction::MUL_INT_LIT8:
+ convertArithOpLit(cUnit, kOpMul, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::DIV_INT_LIT16:
+ case Instruction::DIV_INT_LIT8:
+ convertArithOpLit(cUnit, kOpDiv, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::REM_INT_LIT16:
+ case Instruction::REM_INT_LIT8:
+ convertArithOpLit(cUnit, kOpRem, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::AND_INT_LIT16:
+ case Instruction::AND_INT_LIT8:
+ convertArithOpLit(cUnit, kOpAnd, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::OR_INT_LIT16:
+ case Instruction::OR_INT_LIT8:
+ convertArithOpLit(cUnit, kOpOr, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::XOR_INT_LIT16:
+ case Instruction::XOR_INT_LIT8:
+ convertArithOpLit(cUnit, kOpXor, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::SHL_INT_LIT8:
+ convertArithOpLit(cUnit, kOpLsl, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::SHR_INT_LIT8:
+ convertArithOpLit(cUnit, kOpLsr, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+ case Instruction::USHR_INT_LIT8:
+ convertArithOpLit(cUnit, kOpAsr, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+ break;
+
+ case Instruction::ADD_FLOAT:
+ case Instruction::ADD_FLOAT_2ADDR:
+ case Instruction::ADD_DOUBLE:
+ case Instruction::ADD_DOUBLE_2ADDR:
+ convertFPArithOp(cUnit, kOpAdd, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+
+ case Instruction::SUB_FLOAT:
+ case Instruction::SUB_FLOAT_2ADDR:
+ case Instruction::SUB_DOUBLE:
+ case Instruction::SUB_DOUBLE_2ADDR:
+ convertFPArithOp(cUnit, kOpSub, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+
+ case Instruction::MUL_FLOAT:
+ case Instruction::MUL_FLOAT_2ADDR:
+ case Instruction::MUL_DOUBLE:
+ case Instruction::MUL_DOUBLE_2ADDR:
+ convertFPArithOp(cUnit, kOpMul, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+
+ case Instruction::DIV_FLOAT:
+ case Instruction::DIV_FLOAT_2ADDR:
+ case Instruction::DIV_DOUBLE:
+ case Instruction::DIV_DOUBLE_2ADDR:
+ convertFPArithOp(cUnit, kOpDiv, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+
+ case Instruction::REM_FLOAT:
+ case Instruction::REM_FLOAT_2ADDR:
+ case Instruction::REM_DOUBLE:
+ case Instruction::REM_DOUBLE_2ADDR:
+ convertFPArithOp(cUnit, kOpRem, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+
+#if 0
+
+ case Instruction::MOVE_EXCEPTION: {
+ int exOffset = Thread::ExceptionOffset().Int32Value();
+ rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+#if defined(TARGET_X86)
+ newLIR2(cUnit, kX86Mov32RT, rlResult.lowReg, exOffset);
+ newLIR2(cUnit, kX86Mov32TI, exOffset, 0);
+#else
+ int resetReg = oatAllocTemp(cUnit);
+ loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
+ loadConstant(cUnit, resetReg, 0);
+ storeWordDisp(cUnit, rSELF, exOffset, resetReg);
+ storeValue(cUnit, rlDest, rlResult);
+ oatFreeTemp(cUnit, resetReg);
+#endif
+ break;
+ }
+
+ case Instruction::MOVE_RESULT_WIDE:
+ if (mir->optimizationFlags & MIR_INLINED)
+ break; // Nop - combined w/ previous invoke
+ storeValueWide(cUnit, rlDest, oatGetReturnWide(cUnit, rlDest.fp));
+ break;
+
+ case Instruction::MOVE_RESULT:
+ case Instruction::MOVE_RESULT_OBJECT:
+ if (mir->optimizationFlags & MIR_INLINED)
+ break; // Nop - combined w/ previous invoke
+ storeValue(cUnit, rlDest, oatGetReturn(cUnit, rlDest.fp));
+ break;
+
+ case Instruction::MONITOR_ENTER:
+ genMonitorEnter(cUnit, mir, rlSrc[0]);
+ break;
+
+ case Instruction::MONITOR_EXIT:
+ genMonitorExit(cUnit, mir, rlSrc[0]);
+ break;
+
+ case Instruction::CHECK_CAST:
+ genCheckCast(cUnit, mir, rlSrc[0]);
+ break;
+
+ case Instruction::INSTANCE_OF:
+ genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
+ break;
+
+ case Instruction::NEW_INSTANCE:
+ genNewInstance(cUnit, mir, rlDest);
+ break;
+
+ case Instruction::THROW:
+ genThrow(cUnit, mir, rlSrc[0]);
+ break;
+
+ case Instruction::THROW_VERIFICATION_ERROR:
+ genThrowVerificationError(cUnit, mir);
+ break;
+
+ case Instruction::ARRAY_LENGTH:
+ int lenOffset;
+ lenOffset = Array::LengthOffset().Int32Value();
+ rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
+ genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
+ rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+ loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset, rlResult.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+
+ case Instruction::CONST_STRING:
+ case Instruction::CONST_STRING_JUMBO:
+ genConstString(cUnit, mir, rlDest, rlSrc[0]);
+ break;
+
+ case Instruction::CONST_CLASS:
+ genConstClass(cUnit, mir, rlDest, rlSrc[0]);
+ break;
+
+ case Instruction::FILL_ARRAY_DATA:
+ genFillArrayData(cUnit, mir, rlSrc[0]);
+ break;
+
+ case Instruction::FILLED_NEW_ARRAY:
+ genFilledNewArray(cUnit, mir, false /* not range */);
+ break;
+
+ case Instruction::FILLED_NEW_ARRAY_RANGE:
+ genFilledNewArray(cUnit, mir, true /* range */);
+ break;
+
+ case Instruction::NEW_ARRAY:
+ genNewArray(cUnit, mir, rlDest, rlSrc[0]);
+ break;
+
+ case Instruction::PACKED_SWITCH:
+ genPackedSwitch(cUnit, mir, rlSrc[0]);
+ break;
+
+ case Instruction::SPARSE_SWITCH:
+ genSparseSwitch(cUnit, mir, rlSrc[0], labelList);
+ break;
+
+ case Instruction::CMPL_FLOAT:
+ case Instruction::CMPG_FLOAT:
+ case Instruction::CMPL_DOUBLE:
+ case Instruction::CMPG_DOUBLE:
+ res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+
+ case Instruction::CMP_LONG:
+ genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+ break;
+
+ case Instruction::AGET_WIDE:
+ genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
+ break;
+ case Instruction::AGET:
+ case Instruction::AGET_OBJECT:
+ genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
+ break;
+ case Instruction::AGET_BOOLEAN:
+ genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
+ break;
+ case Instruction::AGET_BYTE:
+ genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
+ break;
+ case Instruction::AGET_CHAR:
+ genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
+ break;
+ case Instruction::AGET_SHORT:
+ genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
+ break;
+ case Instruction::APUT_WIDE:
+ genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
+ break;
+ case Instruction::APUT:
+ genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
+ break;
+ case Instruction::APUT_OBJECT:
+ genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
+ break;
+ case Instruction::APUT_SHORT:
+ case Instruction::APUT_CHAR:
+ genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2], rlSrc[0], 1);
+ break;
+ case Instruction::APUT_BYTE:
+ case Instruction::APUT_BOOLEAN:
+ genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
+ rlSrc[0], 0);
+ break;
+
+ case Instruction::IGET_OBJECT:
+ //case Instruction::IGET_OBJECT_VOLATILE:
+ genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, true);
+ break;
+
+ case Instruction::IGET_WIDE:
+ //case Instruction::IGET_WIDE_VOLATILE:
+ genIGet(cUnit, mir, kLong, rlDest, rlSrc[0], true, false);
+ break;
+
+ case Instruction::IGET:
+ //case Instruction::IGET_VOLATILE:
+ genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, false);
+ break;
+
+ case Instruction::IGET_CHAR:
+ genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0], false, false);
+ break;
+
+ case Instruction::IGET_SHORT:
+ genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0], false, false);
+ break;
+
+ case Instruction::IGET_BOOLEAN:
+ case Instruction::IGET_BYTE:
+ genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0], false, false);
+ break;
+
+ case Instruction::IPUT_WIDE:
+ //case Instruction::IPUT_WIDE_VOLATILE:
+ genIPut(cUnit, mir, kLong, rlSrc[0], rlSrc[1], true, false);
+ break;
+
+ case Instruction::IPUT_OBJECT:
+ //case Instruction::IPUT_OBJECT_VOLATILE:
+ genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, true);
+ break;
+
+ case Instruction::IPUT:
+ //case Instruction::IPUT_VOLATILE:
+ genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, false);
+ break;
+
+ case Instruction::IPUT_BOOLEAN:
+ case Instruction::IPUT_BYTE:
+ genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false, false);
+ break;
+
+ case Instruction::IPUT_CHAR:
+ genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false);
+ break;
+
+ case Instruction::IPUT_SHORT:
+ genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false, false);
+ break;
+
+ case Instruction::SGET_OBJECT:
+ genSget(cUnit, mir, rlDest, false, true);
+ break;
+ case Instruction::SGET:
+ case Instruction::SGET_BOOLEAN:
+ case Instruction::SGET_BYTE:
+ case Instruction::SGET_CHAR:
+ case Instruction::SGET_SHORT:
+ genSget(cUnit, mir, rlDest, false, false);
+ break;
+
+ case Instruction::SGET_WIDE:
+ genSget(cUnit, mir, rlDest, true, false);
+ break;
+
+ case Instruction::SPUT_OBJECT:
+ genSput(cUnit, mir, rlSrc[0], false, true);
+ break;
+
+ case Instruction::SPUT:
+ case Instruction::SPUT_BOOLEAN:
+ case Instruction::SPUT_BYTE:
+ case Instruction::SPUT_CHAR:
+ case Instruction::SPUT_SHORT:
+ genSput(cUnit, mir, rlSrc[0], false, false);
+ break;
+
+ case Instruction::SPUT_WIDE:
+ genSput(cUnit, mir, rlSrc[0], true, false);
+ break;
+
+ case Instruction::INVOKE_STATIC_RANGE:
+ genInvoke(cUnit, bb, mir, kStatic, true /*range*/);
+ break;
+ case Instruction::INVOKE_STATIC:
+ genInvoke(cUnit, bb, mir, kStatic, false /*range*/);
+ break;
+
+ case Instruction::INVOKE_DIRECT:
+ genInvoke(cUnit, bb, mir, kDirect, false /*range*/);
+ break;
+ case Instruction::INVOKE_DIRECT_RANGE:
+ genInvoke(cUnit, bb, mir, kDirect, true /*range*/);
+ break;
+
+ case Instruction::INVOKE_VIRTUAL:
+ genInvoke(cUnit, bb, mir, kVirtual, false /*range*/);
+ break;
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ genInvoke(cUnit, bb, mir, kVirtual, true /*range*/);
+ break;
+
+ case Instruction::INVOKE_SUPER:
+ genInvoke(cUnit, bb, mir, kSuper, false /*range*/);
+ break;
+ case Instruction::INVOKE_SUPER_RANGE:
+ genInvoke(cUnit, bb, mir, kSuper, true /*range*/);
+ break;
+
+ case Instruction::INVOKE_INTERFACE:
+ genInvoke(cUnit, bb, mir, kInterface, false /*range*/);
+ break;
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ genInvoke(cUnit, bb, mir, kInterface, true /*range*/);
+ break;
+
+ case Instruction::NEG_INT:
+ case Instruction::NOT_INT:
+ res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+ break;
+
+ case Instruction::NEG_LONG:
+ case Instruction::NOT_LONG:
+ res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+ break;
+
+ case Instruction::NEG_FLOAT:
+ res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+ break;
+
+ case Instruction::NEG_DOUBLE:
+ res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+ break;
+
+ case Instruction::INT_TO_LONG:
+ genIntToLong(cUnit, mir, rlDest, rlSrc[0]);
+ break;
+
+ case Instruction::LONG_TO_INT:
+ rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
+ rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
+ storeValue(cUnit, rlDest, rlSrc[0]);
+ break;
+
+ case Instruction::INT_TO_BYTE:
+ case Instruction::INT_TO_SHORT:
+ case Instruction::INT_TO_CHAR:
+ genIntNarrowing(cUnit, mir, rlDest, rlSrc[0]);
+ break;
+
+ case Instruction::INT_TO_FLOAT:
+ case Instruction::INT_TO_DOUBLE:
+ case Instruction::LONG_TO_FLOAT:
+ case Instruction::LONG_TO_DOUBLE:
+ case Instruction::FLOAT_TO_INT:
+ case Instruction::FLOAT_TO_LONG:
+ case Instruction::FLOAT_TO_DOUBLE:
+ case Instruction::DOUBLE_TO_INT:
+ case Instruction::DOUBLE_TO_LONG:
+ case Instruction::DOUBLE_TO_FLOAT:
+ genConversion(cUnit, mir);
+ break;
+
+#endif
+
+ default:
+ res = true;
+ }
+ return res;
+}
+
+/* Extended MIR instructions like PHI */
+void convertExtendedMIR(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
+ llvm::BasicBlock* llvmBB)
+{
+
+ switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
+ case kMirOpPhi: {
+ int* incoming = (int*)mir->dalvikInsn.vB;
+ RegLocation rlDest = cUnit->regLocation[mir->ssaRep->defs[0]];
+ llvm::Type* phiType =
+ llvmTypeFromLocRec(cUnit, rlDest);
+ llvm::PHINode* phi = cUnit->irb->CreatePHI(phiType, mir->ssaRep->numUses);
+ for (int i = 0; i < mir->ssaRep->numUses; i++) {
+ RegLocation loc;
+ if (rlDest.wide) {
+ loc = oatGetSrcWide(cUnit, mir, i, i+1);
+ i++;
+ } else {
+ loc = oatGetSrc(cUnit, mir, i);
+ }
+ phi->addIncoming(getLLVMValue(cUnit, loc.origSReg),
+ getLLVMBlock(cUnit, incoming[i]));
+ }
+ defineValue(cUnit, phi, rlDest.origSReg);
+ break;
+ }
+ case kMirOpCopy: {
+ UNIMPLEMENTED(WARNING) << "unimp kMirOpPhi";
+ break;
+ }
+#if defined(TARGET_ARM)
+ case kMirOpFusedCmplFloat:
+ UNIMPLEMENTED(WARNING) << "unimp kMirOpFusedCmpFloat";
+ break;
+ case kMirOpFusedCmpgFloat:
+ UNIMPLEMENTED(WARNING) << "unimp kMirOpFusedCmgFloat";
+ break;
+ case kMirOpFusedCmplDouble:
+ UNIMPLEMENTED(WARNING) << "unimp kMirOpFusedCmplDouble";
+ break;
+ case kMirOpFusedCmpgDouble:
+ UNIMPLEMENTED(WARNING) << "unimp kMirOpFusedCmpgDouble";
+ break;
+ case kMirOpFusedCmpLong:
+ UNIMPLEMENTED(WARNING) << "unimp kMirOpLongCmpBranch";
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+void setDexOffset(CompilationUnit* cUnit, int32_t offset)
+{
+ cUnit->currentDalvikOffset = offset;
+ llvm::SmallVector<llvm::Value*, 1>arrayRef;
+ arrayRef.push_back(cUnit->irb->getInt32(offset));
+ llvm::MDNode* node = llvm::MDNode::get(*cUnit->context, arrayRef);
+ cUnit->irb->SetDexOffset(node);
+}
+
+// Attach method info as metadata to special intrinsic
+void setMethodInfo(CompilationUnit* cUnit)
+{
+ // We don't want dex offset on this
+ cUnit->irb->SetDexOffset(NULL);
+ greenland::IntrinsicHelper::IntrinsicId id;
+ id = greenland::IntrinsicHelper::MethodInfo;
+ llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(id);
+ llvm::Instruction* inst = cUnit->irb->CreateCall(intr);
+ llvm::SmallVector<llvm::Value*, 2> regInfo;
+ regInfo.push_back(cUnit->irb->getInt32(cUnit->numIns));
+ regInfo.push_back(cUnit->irb->getInt32(cUnit->numRegs));
+ regInfo.push_back(cUnit->irb->getInt32(cUnit->numOuts));
+ regInfo.push_back(cUnit->irb->getInt32(cUnit->numCompilerTemps));
+ regInfo.push_back(cUnit->irb->getInt32(cUnit->numSSARegs));
+ llvm::MDNode* regInfoNode = llvm::MDNode::get(*cUnit->context, regInfo);
+ inst->setMetadata("RegInfo", regInfoNode);
+ int promoSize = cUnit->numDalvikRegisters + cUnit->numCompilerTemps + 1;
+ llvm::SmallVector<llvm::Value*, 50> pmap;
+ for (int i = 0; i < promoSize; i++) {
+ PromotionMap* p = &cUnit->promotionMap[i];
+ int32_t mapData = ((p->firstInPair & 0xff) << 24) |
+ ((p->fpReg & 0xff) << 16) |
+ ((p->coreReg & 0xff) << 8) |
+ ((p->fpLocation & 0xf) << 4) |
+ (p->coreLocation & 0xf);
+ pmap.push_back(cUnit->irb->getInt32(mapData));
+ }
+ llvm::MDNode* mapNode = llvm::MDNode::get(*cUnit->context, pmap);
+ inst->setMetadata("PromotionMap", mapNode);
+ setDexOffset(cUnit, cUnit->currentDalvikOffset);
+}
+
+/* Handle the content in each basic block */
+bool methodBlockBitcodeConversion(CompilationUnit* cUnit, BasicBlock* bb)
+{
+ llvm::BasicBlock* llvmBB = getLLVMBlock(cUnit, bb->id);
+ cUnit->irb->SetInsertPoint(llvmBB);
+ setDexOffset(cUnit, bb->startOffset);
+
+ if (bb->blockType == kEntryBlock) {
+ setMethodInfo(cUnit);
+ //genEntrySequence(cUnit, bb);
+ } else if (bb->blockType == kExitBlock) {
+ /*
+ * Because of the differences between how MIR/LIR and llvm handle exit
+ * blocks, we won't explicitly covert them. On the llvm-to-lir
+ * path, it will need to be regenereated.
+ */
+ return false;
+ }
+
+ for (MIR* mir = bb->firstMIRInsn; mir; mir = mir->next) {
+
+ setDexOffset(cUnit, mir->offset);
+
+ Instruction::Code dalvikOpcode = mir->dalvikInsn.opcode;
+ Instruction::Format dalvikFormat = Instruction::FormatOf(dalvikOpcode);
+
+ /* If we're compiling for the debugger, generate an update callout */
+ if (cUnit->genDebugger) {
+ UNIMPLEMENTED(FATAL) << "Need debug codegen";
+ //genDebuggerUpdate(cUnit, mir->offset);
+ }
+
+ if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
+ convertExtendedMIR(cUnit, bb, mir, llvmBB);
+ continue;
+ }
+
+ bool notHandled = convertMIRNode(cUnit, mir, bb, llvmBB,
+ NULL /* labelList */);
+ if (notHandled) {
+ LOG(WARNING) << StringPrintf("%#06x: Op %#x (%s) / Fmt %d not handled",
+ mir->offset, dalvikOpcode,
+ Instruction::Name(dalvikOpcode),
+ dalvikFormat);
+ }
+ }
+
+ if ((bb->taken == NULL) && (bb->fallThrough != NULL) && !bb->hasReturn) {
+ cUnit->irb->CreateBr(getLLVMBlock(cUnit, bb->fallThrough->id));
+ }
+
+ return false;
+}
+
+llvm::FunctionType* getFunctionType(CompilationUnit* cUnit) {
+
+ // Get return type
+ llvm::Type* ret_type = cUnit->irb->GetJType(cUnit->shorty[0],
+ greenland::kAccurate);
+
+ // Get argument type
+ std::vector<llvm::Type*> args_type;
+
+ // method object
+ args_type.push_back(cUnit->irb->GetJMethodTy());
+
+ // Do we have a "this"?
+ if ((cUnit->access_flags & kAccStatic) == 0) {
+ args_type.push_back(cUnit->irb->GetJObjectTy());
+ }
+
+ for (uint32_t i = 1; i < strlen(cUnit->shorty); ++i) {
+ args_type.push_back(cUnit->irb->GetJType(cUnit->shorty[i],
+ greenland::kAccurate));
+ }
+
+ return llvm::FunctionType::get(ret_type, args_type, false);
+}
+
+bool createFunction(CompilationUnit* cUnit) {
+ std::string func_name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file,
+ /* with_signature */ false));
+ llvm::FunctionType* func_type = getFunctionType(cUnit);
+
+ if (func_type == NULL) {
+ return false;
+ }
+
+ cUnit->func = llvm::Function::Create(func_type,
+ llvm::Function::ExternalLinkage,
+ func_name, cUnit->module);
+
+ llvm::Function::arg_iterator arg_iter(cUnit->func->arg_begin());
+ llvm::Function::arg_iterator arg_end(cUnit->func->arg_end());
+
+ arg_iter->setName("method");
+ ++arg_iter;
+
+ int startSReg = cUnit->numRegs;
+
+ for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) {
+ arg_iter->setName(StringPrintf("v%i_0", startSReg));
+ startSReg += cUnit->regLocation[startSReg].wide ? 2 : 1;
+ }
+
+ return true;
+}
+
+bool createLLVMBasicBlock(CompilationUnit* cUnit, BasicBlock* bb)
+{
+ // Skip the exit block
+ if (bb->blockType == kExitBlock) {
+ cUnit->idToBlockMap.Put(bb->id, NULL);
+ } else {
+ int offset = bb->startOffset;
+ bool entryBlock = (bb->blockType == kEntryBlock);
+ llvm::BasicBlock* llvmBB =
+ llvm::BasicBlock::Create(*cUnit->context, entryBlock ? "entry" :
+ StringPrintf(labelFormat, offset, bb->id),
+ cUnit->func);
+ if (entryBlock) {
+ cUnit->entryBB = llvmBB;
+ cUnit->placeholderBB =
+ llvm::BasicBlock::Create(*cUnit->context, "placeholder",
+ cUnit->func);
+ }
+ cUnit->idToBlockMap.Put(bb->id, llvmBB);
+ }
+ return false;
+}
+
+
+/*
+ * Convert MIR to LLVM_IR
+ * o For each ssa name, create LLVM named value. Type these
+ * appropriately, and ignore high half of wide and double operands.
+ * o For each MIR basic block, create an LLVM basic block.
+ * o Iterate through the MIR a basic block at a time, setting arguments
+ * to recovered ssa name.
+ */
+void oatMethodMIR2Bitcode(CompilationUnit* cUnit)
+{
+ initIR(cUnit);
+ oatInitGrowableList(cUnit, &cUnit->llvmValues, cUnit->numSSARegs);
+
+ // Create the function
+ createFunction(cUnit);
+
+ // Create an LLVM basic block for each MIR block in dfs preorder
+ oatDataFlowAnalysisDispatcher(cUnit, createLLVMBasicBlock,
+ kPreOrderDFSTraversal, false /* isIterative */);
+ /*
+ * Create an llvm named value for each MIR SSA name. Note: we'll use
+ * placeholders for all non-argument values (because we haven't seen
+ * the definition yet).
+ */
+ cUnit->irb->SetInsertPoint(cUnit->placeholderBB);
+ llvm::Function::arg_iterator arg_iter(cUnit->func->arg_begin());
+ arg_iter++; /* Skip path method */
+ for (int i = 0; i < cUnit->numSSARegs; i++) {
+ llvm::Value* val;
+ llvm::Type* ty = llvmTypeFromLocRec(cUnit, cUnit->regLocation[i]);
+ if (i < cUnit->numRegs) {
+ // Skip non-argument _0 names - should never be a use
+ oatInsertGrowableList(cUnit, &cUnit->llvmValues, (intptr_t)0);
+ } else if (i >= (cUnit->numRegs + cUnit->numIns)) {
+ // Handle SSA defs, skipping Method* and compiler temps
+ if (SRegToVReg(cUnit, i) < 0) {
+ val = NULL;
+ } else {
+ val = cUnit->irb->CreateLoad(cUnit->irb->CreateAlloca(ty, 0));
+ val->setName(llvmSSAName(cUnit, i));
+ }
+ oatInsertGrowableList(cUnit, &cUnit->llvmValues, (intptr_t)val);
+ if (cUnit->regLocation[i].wide) {
+ // Skip high half of wide values
+ oatInsertGrowableList(cUnit, &cUnit->llvmValues, 0);
+ i++;
+ }
+ } else {
+ // Recover previously-created argument values
+ llvm::Value* argVal = arg_iter++;
+ oatInsertGrowableList(cUnit, &cUnit->llvmValues, (intptr_t)argVal);
+ }
+ }
+ cUnit->irb->CreateBr(cUnit->placeholderBB);
+
+ oatDataFlowAnalysisDispatcher(cUnit, methodBlockBitcodeConversion,
+ kPreOrderDFSTraversal, false /* Iterative */);
+
+ cUnit->placeholderBB->eraseFromParent();
+
+ llvm::verifyFunction(*cUnit->func, llvm::PrintMessageAction);
+
+ // Write bitcode to file
+ std::string errmsg;
+
+ llvm::OwningPtr<llvm::tool_output_file> out_file(
+ new llvm::tool_output_file("/tmp/foo.bc", errmsg,
+ llvm::raw_fd_ostream::F_Binary));
+
+ if (!errmsg.empty()) {
+ LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
+ }
+
+ llvm::WriteBitcodeToFile(cUnit->module, out_file->os());
+ out_file->keep();
+
+
+}
+
+RegLocation getLoc(CompilationUnit* cUnit, llvm::Value* val) {
+ RegLocation res;
+ SafeMap<llvm::Value*, RegLocation>::iterator it = cUnit->locMap.find(val);
+ if (it == cUnit->locMap.end()) {
+ const char* valName = val->getName().str().c_str();
+ DCHECK(valName != NULL);
+ DCHECK(strlen(valName) > 0);
+ if (valName[0] == 'v') {
+ int baseSReg = INVALID_SREG;
+ sscanf(valName, "v%d_", &baseSReg);
+ res = cUnit->regLocation[baseSReg];
+ cUnit->locMap.Put(val, res);
+ } else {
+ UNIMPLEMENTED(WARNING) << "Need to handle llvm temps";
+ DCHECK(valName[0] == 't');
+ }
+ } else {
+ res = it->second;
+ }
+ return res;
+}
+
+Instruction::Code getDalvikOpcode(OpKind op, bool isConst, bool isWide)
+{
+ Instruction::Code res = Instruction::NOP;
+ if (isWide) {
+ switch(op) {
+ case kOpAdd: res = Instruction::ADD_LONG; break;
+ case kOpSub: res = Instruction::SUB_LONG; break;
+ case kOpMul: res = Instruction::MUL_LONG; break;
+ case kOpDiv: res = Instruction::DIV_LONG; break;
+ case kOpRem: res = Instruction::REM_LONG; break;
+ case kOpAnd: res = Instruction::AND_LONG; break;
+ case kOpOr: res = Instruction::OR_LONG; break;
+ case kOpXor: res = Instruction::XOR_LONG; break;
+ case kOpLsl: res = Instruction::SHL_LONG; break;
+ case kOpLsr: res = Instruction::USHR_LONG; break;
+ case kOpAsr: res = Instruction::SHR_LONG; break;
+ default: LOG(FATAL) << "Unexpected OpKind " << op;
+ }
+ } else if (isConst){
+ switch(op) {
+ case kOpAdd: res = Instruction::ADD_INT_LIT16; break;
+ case kOpSub: res = Instruction::RSUB_INT_LIT8; break;
+ case kOpMul: res = Instruction::MUL_INT_LIT16; break;
+ case kOpDiv: res = Instruction::DIV_INT_LIT16; break;
+ case kOpRem: res = Instruction::REM_INT_LIT16; break;
+ case kOpAnd: res = Instruction::AND_INT_LIT16; break;
+ case kOpOr: res = Instruction::OR_INT_LIT16; break;
+ case kOpXor: res = Instruction::XOR_INT_LIT16; break;
+ case kOpLsl: res = Instruction::SHL_INT_LIT8; break;
+ case kOpLsr: res = Instruction::USHR_INT_LIT8; break;
+ case kOpAsr: res = Instruction::SHR_INT_LIT8; break;
+ default: LOG(FATAL) << "Unexpected OpKind " << op;
+ }
+ } else {
+ switch(op) {
+ case kOpAdd: res = Instruction::ADD_INT; break;
+ case kOpSub: res = Instruction::SUB_INT; break;
+ case kOpMul: res = Instruction::MUL_INT; break;
+ case kOpDiv: res = Instruction::DIV_INT; break;
+ case kOpRem: res = Instruction::REM_INT; break;
+ case kOpAnd: res = Instruction::AND_INT; break;
+ case kOpOr: res = Instruction::OR_INT; break;
+ case kOpXor: res = Instruction::XOR_INT; break;
+ case kOpLsl: res = Instruction::SHL_INT; break;
+ case kOpLsr: res = Instruction::USHR_INT; break;
+ case kOpAsr: res = Instruction::SHR_INT; break;
+ default: LOG(FATAL) << "Unexpected OpKind " << op;
+ }
+ }
+ return res;
+}
+
+void cvtBinOp(CompilationUnit* cUnit, OpKind op, llvm::Instruction* inst)
+{
+ RegLocation rlDest = getLoc(cUnit, inst);
+ llvm::Value* lhs = inst->getOperand(0);
+ DCHECK(llvm::dyn_cast<llvm::ConstantInt>(lhs) == NULL);
+ RegLocation rlSrc1 = getLoc(cUnit, inst->getOperand(0));
+ llvm::Value* rhs = inst->getOperand(1);
+ if (llvm::ConstantInt* src2 = llvm::dyn_cast<llvm::ConstantInt>(rhs)) {
+ Instruction::Code dalvikOp = getDalvikOpcode(op, true, false);
+ genArithOpIntLit(cUnit, dalvikOp, rlDest, rlSrc1, src2->getSExtValue());
+ } else {
+ Instruction::Code dalvikOp = getDalvikOpcode(op, false, rlDest.wide);
+ RegLocation rlSrc2 = getLoc(cUnit, rhs);
+ if (rlDest.wide) {
+ genArithOpLong(cUnit, dalvikOp, rlDest, rlSrc1, rlSrc2);
+ } else {
+ genArithOpInt(cUnit, dalvikOp, rlDest, rlSrc1, rlSrc2);
+ }
+ }
+}
+
+void cvtBr(CompilationUnit* cUnit, llvm::Instruction* inst)
+{
+ llvm::BranchInst* brInst = llvm::dyn_cast<llvm::BranchInst>(inst);
+ DCHECK(brInst != NULL);
+ DCHECK(brInst->isUnconditional()); // May change - but this is all we use now
+ llvm::BasicBlock* targetBB = brInst->getSuccessor(0);
+ opUnconditionalBranch(cUnit, cUnit->blockToLabelMap.Get(targetBB));
+}
+
+void cvtPhi(CompilationUnit* cUnit, llvm::Instruction* inst)
+{
+ // Nop - these have already been processed
+}
+
+void cvtRet(CompilationUnit* cUnit, llvm::Instruction* inst)
+{
+ llvm::ReturnInst* retInst = llvm::dyn_cast<llvm::ReturnInst>(inst);
+ llvm::Value* retVal = retInst->getReturnValue();
+ if (retVal != NULL) {
+ RegLocation rlSrc = getLoc(cUnit, retVal);
+ if (rlSrc.wide) {
+ storeValueWide(cUnit, oatGetReturnWide(cUnit, rlSrc.fp), rlSrc);
+ } else {
+ storeValue(cUnit, oatGetReturn(cUnit, rlSrc.fp), rlSrc);
+ }
+ }
+ genExitSequence(cUnit);
+}
+
+ConditionCode getCond(llvm::ICmpInst::Predicate llvmCond)
+{
+ ConditionCode res = kCondAl;
+ switch(llvmCond) {
+ case llvm::ICmpInst::ICMP_NE: res = kCondNe; break;
+ case llvm::ICmpInst::ICMP_SGT: res = kCondGt; break;
+ default: LOG(FATAL) << "Unexpected llvm condition";
+ }
+ return res;
+}
+
+void cvtICmp(CompilationUnit* cUnit, llvm::Instruction* inst)
+{
+ // genCmpLong(cUnit, rlDest, rlSrc1, rlSrc2)
+ UNIMPLEMENTED(FATAL);
+}
+
+void cvtICmpBr(CompilationUnit* cUnit, llvm::Instruction* inst,
+ llvm::BranchInst* brInst)
+{
+ // Get targets
+ llvm::BasicBlock* takenBB = brInst->getSuccessor(0);
+ LIR* taken = cUnit->blockToLabelMap.Get(takenBB);
+ llvm::BasicBlock* fallThroughBB = brInst->getSuccessor(1);
+ LIR* fallThrough = cUnit->blockToLabelMap.Get(fallThroughBB);
+ // Get comparison operands
+ llvm::ICmpInst* iCmpInst = llvm::dyn_cast<llvm::ICmpInst>(inst);
+ ConditionCode cond = getCond(iCmpInst->getPredicate());
+ llvm::Value* lhs = iCmpInst->getOperand(0);
+ // Not expecting a constant as 1st operand
+ DCHECK(llvm::dyn_cast<llvm::ConstantInt>(lhs) == NULL);
+ RegLocation rlSrc1 = getLoc(cUnit, inst->getOperand(0));
+ rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+ llvm::Value* rhs = inst->getOperand(1);
+#if defined(TARGET_MIPS)
+ // Compare and branch in one shot
+ (void)taken;
+ (void)cond;
+ (void)rhs;
+ UNIMPLEMENTED(FATAL);
+#else
+ //Compare, then branch
+ // TODO: handle fused CMP_LONG/IF_xxZ case
+ if (llvm::ConstantInt* src2 = llvm::dyn_cast<llvm::ConstantInt>(rhs)) {
+ opRegImm(cUnit, kOpCmp, rlSrc1.lowReg, src2->getSExtValue());
+ } else {
+ RegLocation rlSrc2 = getLoc(cUnit, rhs);
+ rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+ opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
+ }
+ opCondBranch(cUnit, cond, taken);
+#endif
+ // Fallthrough
+ opUnconditionalBranch(cUnit, fallThrough);
+}
+
+void cvtCall(CompilationUnit* cUnit, llvm::CallInst* callInst,
+ llvm::Function* callee)
+{
+ UNIMPLEMENTED(FATAL);
+}
+
+void setMethodInfo(CompilationUnit* cUnit, llvm::CallInst* callInst)
+{
+ UNIMPLEMENTED(WARNING) << "Net setMethodInfo";
+}
+
+void cvtCopy(CompilationUnit* cUnit, llvm::CallInst* callInst)
+{
+ DCHECK(callInst->getNumArgOperands() == 1);
+ RegLocation rlSrc = getLoc(cUnit, callInst->getArgOperand(0));
+ RegLocation rlDest = getLoc(cUnit, callInst);
+ if (rlSrc.wide) {
+ storeValueWide(cUnit, rlDest, rlSrc);
+ } else {
+ storeValue(cUnit, rlDest, rlSrc);
+ }
+}
+
+// Note: Immediate arg is a ConstantInt regardless of result type
+void cvtConst(CompilationUnit* cUnit, llvm::CallInst* callInst)
+{
+ DCHECK(callInst->getNumArgOperands() == 1);
+ llvm::ConstantInt* src =
+ llvm::dyn_cast<llvm::ConstantInt>(callInst->getArgOperand(0));
+ uint64_t immval = src->getZExtValue();
+ RegLocation rlDest = getLoc(cUnit, callInst);
+ RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+ if (rlDest.wide) {
+ loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+ (immval) & 0xffffffff, (immval >> 32) & 0xffffffff);
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else {
+ loadConstantNoClobber(cUnit, rlResult.lowReg, immval & 0xffffffff);
+ storeValue(cUnit, rlDest, rlResult);
+ }
+}
+
+bool methodBitcodeBlockCodeGen(CompilationUnit* cUnit, llvm::BasicBlock* bb)
+{
+ bool isEntry = (bb == &cUnit->func->getEntryBlock());
+ // Define the starting label
+ LIR* blockLabel = cUnit->blockToLabelMap.Get(bb);
+ // Extract the starting offset from the block's name
+ if (!isEntry) {
+ const char* blockName = bb->getName().str().c_str();
+ int dummy;
+ sscanf(blockName, labelFormat, &blockLabel->operands[0], &dummy);
+ }
+ // Set the label kind
+ blockLabel->opcode = kPseudoNormalBlockLabel;
+ // Insert the label
+ oatAppendLIR(cUnit, blockLabel);
+
+ // Free temp registers and reset redundant store tracking */
+ oatResetRegPool(cUnit);
+ oatResetDefTracking(cUnit);
+
+ //TODO: restore oat incoming liveness optimization
+ oatClobberAllRegs(cUnit);
+
+ //LIR* headLIR = NULL;
+
+
+ if (isEntry) {
+ cUnit->currentDalvikOffset = 0;
+ genEntrySequence(cUnit);
+ }
+
+ // Visit all of the instructions in the block
+ for (llvm::BasicBlock::iterator it = bb->begin(), e = bb->end(); it != e;) {
+ llvm::Instruction* inst = it;
+ llvm::BasicBlock::iterator nextIt = ++it;
+ // Extract the Dalvik offset from the instruction
+ uint32_t opcode = inst->getOpcode();
+ llvm::MDNode* dexOffsetNode = inst->getMetadata("DexOff");
+ if (dexOffsetNode != NULL) {
+ llvm::ConstantInt* dexOffsetValue =
+ static_cast<llvm::ConstantInt*>(dexOffsetNode->getOperand(0));
+ cUnit->currentDalvikOffset = dexOffsetValue->getZExtValue();
+ }
+
+ switch(opcode) {
+
+ case llvm::Instruction::ICmp: {
+ llvm::Instruction* nextInst = nextIt;
+ llvm::BranchInst* brInst = llvm::dyn_cast<llvm::BranchInst>(nextInst);
+ if (brInst != NULL /* and... */) {
+ cvtICmpBr(cUnit, inst, brInst);
+ ++it;
+ } else {
+ cvtICmp(cUnit, inst);
+ }
+ }
+ break;
+
+ case llvm::Instruction::Call: {
+ llvm::CallInst* callInst = llvm::dyn_cast<llvm::CallInst>(inst);
+ llvm::Function* callee = callInst->getCalledFunction();
+ greenland::IntrinsicHelper::IntrinsicId id =
+ cUnit->intrinsic_helper->GetIntrinsicId(callee);
+ switch (id) {
+ case greenland::IntrinsicHelper::CopyInt:
+ case greenland::IntrinsicHelper::CopyObj:
+ case greenland::IntrinsicHelper::CopyFloat:
+ case greenland::IntrinsicHelper::CopyLong:
+ case greenland::IntrinsicHelper::CopyDouble:
+ cvtCopy(cUnit, callInst);
+ break;
+ case greenland::IntrinsicHelper::ConstInt:
+ case greenland::IntrinsicHelper::ConstObj:
+ case greenland::IntrinsicHelper::ConstLong:
+ case greenland::IntrinsicHelper::ConstFloat:
+ case greenland::IntrinsicHelper::ConstDouble:
+ cvtConst(cUnit, callInst);
+ break;
+ case greenland::IntrinsicHelper::MethodInfo:
+ setMethodInfo(cUnit, callInst);
+ break;
+ case greenland::IntrinsicHelper::CheckSuspend:
+ genSuspendTest(cUnit, 0 /* optFlags already applied */);
+ break;
+ case greenland::IntrinsicHelper::UnknownId:
+ cvtCall(cUnit, callInst, callee);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected intrinsic " << (int)id << ", "
+ << cUnit->intrinsic_helper->GetName(id);
+ }
+ }
+ break;
+
+ case llvm::Instruction::Br: cvtBr(cUnit, inst); break;
+ case llvm::Instruction::Add: cvtBinOp(cUnit, kOpAdd, inst); break;
+ case llvm::Instruction::Sub: cvtBinOp(cUnit, kOpSub, inst); break;
+ case llvm::Instruction::Mul: cvtBinOp(cUnit, kOpMul, inst); break;
+ case llvm::Instruction::SDiv: cvtBinOp(cUnit, kOpDiv, inst); break;
+ case llvm::Instruction::SRem: cvtBinOp(cUnit, kOpRem, inst); break;
+ case llvm::Instruction::And: cvtBinOp(cUnit, kOpAnd, inst); break;
+ case llvm::Instruction::Or: cvtBinOp(cUnit, kOpOr, inst); break;
+ case llvm::Instruction::Xor: cvtBinOp(cUnit, kOpXor, inst); break;
+ case llvm::Instruction::Shl: cvtBinOp(cUnit, kOpLsl, inst); break;
+ case llvm::Instruction::LShr: cvtBinOp(cUnit, kOpLsr, inst); break;
+ case llvm::Instruction::AShr: cvtBinOp(cUnit, kOpAsr, inst); break;
+ case llvm::Instruction::PHI: cvtPhi(cUnit, inst); break;
+ case llvm::Instruction::Ret: cvtRet(cUnit, inst); break;
+
+ case llvm::Instruction::Invoke:
+ case llvm::Instruction::FAdd:
+ case llvm::Instruction::FSub:
+ case llvm::Instruction::FMul:
+ case llvm::Instruction::FDiv:
+ case llvm::Instruction::FRem:
+ case llvm::Instruction::Trunc:
+ case llvm::Instruction::ZExt:
+ case llvm::Instruction::SExt:
+ case llvm::Instruction::FPToUI:
+ case llvm::Instruction::FPToSI:
+ case llvm::Instruction::UIToFP:
+ case llvm::Instruction::SIToFP:
+ case llvm::Instruction::FPTrunc:
+ case llvm::Instruction::FPExt:
+ case llvm::Instruction::PtrToInt:
+ case llvm::Instruction::IntToPtr:
+ case llvm::Instruction::Switch:
+ case llvm::Instruction::FCmp:
+ UNIMPLEMENTED(FATAL) << "Unimplemented llvm opcode: " << opcode; break;
+
+ case llvm::Instruction::URem:
+ case llvm::Instruction::UDiv:
+ case llvm::Instruction::Resume:
+ case llvm::Instruction::Unreachable:
+ case llvm::Instruction::Alloca:
+ case llvm::Instruction::GetElementPtr:
+ case llvm::Instruction::Fence:
+ case llvm::Instruction::AtomicCmpXchg:
+ case llvm::Instruction::AtomicRMW:
+ case llvm::Instruction::BitCast:
+ case llvm::Instruction::VAArg:
+ case llvm::Instruction::Select:
+ case llvm::Instruction::UserOp1:
+ case llvm::Instruction::UserOp2:
+ case llvm::Instruction::ExtractElement:
+ case llvm::Instruction::InsertElement:
+ case llvm::Instruction::ShuffleVector:
+ case llvm::Instruction::ExtractValue:
+ case llvm::Instruction::InsertValue:
+ case llvm::Instruction::LandingPad:
+ case llvm::Instruction::IndirectBr:
+ case llvm::Instruction::Load:
+ case llvm::Instruction::Store:
+ LOG(FATAL) << "Unexpected llvm opcode: " << opcode; break;
+
+ default:
+ LOG(FATAL) << "Unknown llvm opcode: " << opcode; break;
+ }
+ }
+ return false;
+}
+
+/*
+ * Convert LLVM_IR to MIR:
+ * o Iterate through the LLVM_IR and construct a graph using
+ * standard MIR building blocks.
+ * o Perform a basic-block optimization pass to remove unnecessary
+ * store/load sequences.
+ * o Convert the LLVM Value operands into RegLocations where applicable.
+ * o Create ssaRep def/use operand arrays for each converted LLVM opcode
+ * o Perform register promotion
+ * o Iterate through the graph a basic block at a time, generating
+ * LIR.
+ * o Assemble LIR as usual.
+ * o Profit.
+ */
+void oatMethodBitcode2LIR(CompilationUnit* cUnit)
+{
+ int numBasicBlocks = cUnit->func->getBasicBlockList().size();
+ // Allocate a list for LIR basic block labels
+ cUnit->blockLabelList =
+ (void*)oatNew(cUnit, sizeof(LIR) * numBasicBlocks, true, kAllocLIR);
+ LIR* labelList = (LIR*)cUnit->blockLabelList;
+ int nextLabel = 0;
+ for (llvm::Function::iterator i = cUnit->func->begin(),
+ e = cUnit->func->end(); i != e; ++i) {
+ cUnit->blockToLabelMap.Put(static_cast<llvm::BasicBlock*>(i),
+ &labelList[nextLabel++]);
+ }
+ // Walk the blocks, generating code.
+ for (llvm::Function::iterator i = cUnit->func->begin(),
+ e = cUnit->func->end(); i != e; ++i) {
+ methodBitcodeBlockCodeGen(cUnit, static_cast<llvm::BasicBlock*>(i));
+ }
+
+ handleSuspendLaunchpads(cUnit);
+
+ handleThrowLaunchpads(cUnit);
+
+ handleIntrinsicLaunchpads(cUnit);
+
+ freeIR(cUnit);
+}
+
+
+} // namespace art
+
+#endif // ART_USE_QUICK_COMPILER
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 9c51f0a..15dbedd 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -21,8 +21,9 @@
#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
(1 << kDebugDisplayMissingTargets))
-const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0,
- INVALID_REG, INVALID_REG, INVALID_SREG};
+const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0,
+ INVALID_REG, INVALID_REG, INVALID_SREG,
+ INVALID_SREG};
/* Mark register usage state and return long retloc */
RegLocation oatGetReturnWide(CompilationUnit* cUnit, bool isDouble)
@@ -851,9 +852,9 @@
LIR* headLIR = NULL;
if (bb->blockType == kEntryBlock) {
- genEntrySequence(cUnit, bb);
+ genEntrySequence(cUnit);
} else if (bb->blockType == kExitBlock) {
- genExitSequence(cUnit, bb);
+ genExitSequence(cUnit);
}
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index bc30335..c0d91a4 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -56,7 +56,7 @@
return rLR;
}
-void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
+void genEntrySequence(CompilationUnit* cUnit)
{
int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
/*
@@ -116,7 +116,7 @@
oatFreeTemp(cUnit, r3);
}
-void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
+void genExitSequence(CompilationUnit* cUnit)
{
int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
/*
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index 93e7878..4004fbb 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -125,10 +125,10 @@
#define rNone (-1)
/* RegisterLocation templates return values (r0, or r0/r1) */
-#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 0, 1, r0, INVALID_REG,\
- INVALID_SREG}
-#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, r0, r1, \
- INVALID_SREG}
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, r0, INVALID_REG,\
+ INVALID_SREG, INVALID_SREG}
+#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1, \
+ INVALID_SREG, INVALID_SREG}
#define LOC_C_RETURN_FLOAT LOC_C_RETURN
#define LOC_C_RETURN_WIDE_DOUBLE LOC_C_RETURN_WIDE
diff --git a/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc b/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc
index f7132ab..660d095 100644
--- a/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc
+++ b/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc
@@ -45,6 +45,9 @@
/* Thumb2-specific register allocation */
#include "../Thumb2/Ralloc.cc"
+/* Bitcode conversion */
+#include "../../MethodBitcode.cc"
+
/* MIR2LIR dispatcher and architectural independent codegen routines */
#include "../../MethodCodegenDriver.cc"
diff --git a/src/compiler/codegen/arm/armv7-a/Codegen.cc b/src/compiler/codegen/arm/armv7-a/Codegen.cc
index 6f62ccf..ba1e7ab 100644
--- a/src/compiler/codegen/arm/armv7-a/Codegen.cc
+++ b/src/compiler/codegen/arm/armv7-a/Codegen.cc
@@ -45,6 +45,9 @@
/* Thumb2-specific register allocation */
#include "../Thumb2/Ralloc.cc"
+/* Bitcode conversion */
+#include "../../MethodBitcode.cc"
+
/* MIR2LIR dispatcher and architectural independent codegen routines */
#include "../../MethodCodegenDriver.cc"
diff --git a/src/compiler/codegen/mips/ArchFactory.cc b/src/compiler/codegen/mips/ArchFactory.cc
index 4fd127f..bf4c8a6 100644
--- a/src/compiler/codegen/mips/ArchFactory.cc
+++ b/src/compiler/codegen/mips/ArchFactory.cc
@@ -144,7 +144,7 @@
opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize);
}
-void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
+void genEntrySequence(CompilationUnit* cUnit)
{
int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
/*
@@ -198,7 +198,7 @@
oatFreeTemp(cUnit, rARG3);
}
-void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
+void genExitSequence(CompilationUnit* cUnit)
{
/*
* In the exit path, rRET0/rRET1 are live - make sure they aren't
diff --git a/src/compiler/codegen/mips/MipsLIR.h b/src/compiler/codegen/mips/MipsLIR.h
index c9f917b..4850205 100644
--- a/src/compiler/codegen/mips/MipsLIR.h
+++ b/src/compiler/codegen/mips/MipsLIR.h
@@ -145,16 +145,16 @@
#define r_FRESULT1 r_F1
/* RegisterLocation templates return values (r_V0, or r_V0/r_V1) */
-#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 0, 1, r_V0, INVALID_REG, \
- INVALID_SREG}
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, r_V0, INVALID_REG, \
+ INVALID_SREG, INVALID_SREG}
#define LOC_C_RETURN_FLOAT LOC_C_RETURN
-#define LOC_C_RETURN_ALT {kLocPhysReg, 0, 0, 0, 0, 0, 0, 1, r_F0, INVALID_REG, \
- INVALID_SREG}
-#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, r_RESULT0, \
- r_RESULT1, INVALID_SREG}
+#define LOC_C_RETURN_ALT {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, r_F0, \
+ INVALID_REG, INVALID_SREG, INVALID_SREG}
+#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r_RESULT0, \
+ r_RESULT1, INVALID_SREG, INVALID_SREG}
#define LOC_C_RETURN_WIDE_DOUBLE LOC_C_RETURN_WIDE
-#define LOC_C_RETURN_WIDE_ALT {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, r_FRESULT0,\
- r_FRESULT1, INVALID_SREG}
+#define LOC_C_RETURN_WIDE_ALT {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r_FRESULT0,\
+ r_FRESULT1, INVALID_SREG, INVALID_SREG}
enum ResourceEncodingPos {
kGPReg0 = 0,
diff --git a/src/compiler/codegen/mips/mips/Codegen.cc b/src/compiler/codegen/mips/mips/Codegen.cc
index 71f43e5..60a7646 100644
--- a/src/compiler/codegen/mips/mips/Codegen.cc
+++ b/src/compiler/codegen/mips/mips/Codegen.cc
@@ -45,6 +45,9 @@
/* Mips32-specific register allocation */
#include "../Mips32/Ralloc.cc"
+/* Bitcode conversion */
+#include "../../MethodBitcode.cc"
+
/* MIR2LIR dispatcher and architectural independent codegen routines */
#include "../../MethodCodegenDriver.cc"
diff --git a/src/compiler/codegen/x86/ArchFactory.cc b/src/compiler/codegen/x86/ArchFactory.cc
index 9e6ef09..b3cebdc 100644
--- a/src/compiler/codegen/x86/ArchFactory.cc
+++ b/src/compiler/codegen/x86/ArchFactory.cc
@@ -34,7 +34,8 @@
// Compute (r1:r0) = (r1:r0) + (r2:r3)
opRegReg(cUnit, kOpAdd, r0, r2); // r0 = r0 + r2
opRegReg(cUnit, kOpAdc, r1, r3); // r1 = r1 + r3 + CF
- RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
+ RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
+ INVALID_SREG, INVALID_SREG};
storeValueWide(cUnit, rlDest, rlResult);
return false;
}
@@ -49,7 +50,8 @@
// Compute (r1:r0) = (r1:r0) + (r2:r3)
opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
- RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
+ RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
+ INVALID_SREG, INVALID_SREG};
storeValueWide(cUnit, rlDest, rlResult);
return false;
}
@@ -64,7 +66,8 @@
// Compute (r1:r0) = (r1:r0) + (r2:r3)
opRegReg(cUnit, kOpAnd, r0, r2); // r0 = r0 - r2
opRegReg(cUnit, kOpAnd, r1, r3); // r1 = r1 - r3 - CF
- RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
+ RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
+ INVALID_SREG, INVALID_SREG};
storeValueWide(cUnit, rlDest, rlResult);
return false;
}
@@ -79,7 +82,8 @@
// Compute (r1:r0) = (r1:r0) + (r2:r3)
opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 - r2
opRegReg(cUnit, kOpOr, r1, r3); // r1 = r1 - r3 - CF
- RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
+ RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
+ INVALID_SREG, INVALID_SREG};
storeValueWide(cUnit, rlDest, rlResult);
return false;
}
@@ -94,7 +98,8 @@
// Compute (r1:r0) = (r1:r0) + (r2:r3)
opRegReg(cUnit, kOpXor, r0, r2); // r0 = r0 - r2
opRegReg(cUnit, kOpXor, r1, r3); // r1 = r1 - r3 - CF
- RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
+ RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
+ INVALID_SREG, INVALID_SREG};
storeValueWide(cUnit, rlDest, rlResult);
return false;
}
@@ -109,7 +114,8 @@
opRegReg(cUnit, kOpNeg, r0, r0); // r0 = -r0
opRegImm(cUnit, kOpAdc, r1, 0); // r1 = r1 + CF
opRegReg(cUnit, kOpNeg, r1, r1); // r1 = -r1
- RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
+ RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
+ INVALID_SREG, INVALID_SREG};
storeValueWide(cUnit, rlDest, rlResult);
return false;
}
@@ -157,7 +163,7 @@
newLIR2(cUnit, opcode, rDest, threadOffset);
}
-void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
+void genEntrySequence(CompilationUnit* cUnit)
{
/*
* On entry, rARG0, rARG1, rARG2 are live. Let the register
@@ -210,7 +216,7 @@
oatFreeTemp(cUnit, rARG2);
}
-void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb) {
+void genExitSequence(CompilationUnit* cUnit) {
/*
* In the exit path, rRET0/rRET1 are live - make sure they aren't
* allocated by the register utilities as temps.
diff --git a/src/compiler/codegen/x86/X86LIR.h b/src/compiler/codegen/x86/X86LIR.h
index 3ec1112..6e7dcee 100644
--- a/src/compiler/codegen/x86/X86LIR.h
+++ b/src/compiler/codegen/x86/X86LIR.h
@@ -137,11 +137,11 @@
#define rNone (-1)
/* RegisterLocation templates return values (rAX, rAX/rDX or XMM0) */
-// location, wide, defined, fp, core, ref, highWord, home, lowReg, highReg, sRegLow
-#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 0, 1, rAX, INVALID_REG, INVALID_SREG}
-#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 0, 1, rAX, rDX, INVALID_SREG}
-#define LOC_C_RETURN_FLOAT {kLocPhysReg, 0, 0, 1, 0, 0, 0, 1, fr0, INVALID_REG, INVALID_SREG}
-#define LOC_C_RETURN_WIDE_DOUBLE {kLocPhysReg, 1, 0, 1, 0, 0, 0, 1, fr0, fr1, INVALID_SREG}
+// location, wide, defined, const, fp, core, ref, highWord, home, lowReg, highReg, sRegLow
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, rAX, INVALID_REG, INVALID_SREG, INVALID_SREG}
+#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, rAX, rDX, INVALID_SREG, INVALID_SREG}
+#define LOC_C_RETURN_FLOAT {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1, fr0, INVALID_REG, INVALID_SREG, INVALID_SREG}
+#define LOC_C_RETURN_WIDE_DOUBLE {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1, fr0, fr1, INVALID_SREG, INVALID_SREG}
enum ResourceEncodingPos {
kGPReg0 = 0,
diff --git a/src/compiler/codegen/x86/x86/Codegen.cc b/src/compiler/codegen/x86/x86/Codegen.cc
index f8719d9..0552ce3 100644
--- a/src/compiler/codegen/x86/x86/Codegen.cc
+++ b/src/compiler/codegen/x86/x86/Codegen.cc
@@ -44,6 +44,9 @@
/* X86-specific register allocation */
#include "../X86/Ralloc.cc"
+/* Bitcode conversion */
+#include "../../MethodBitcode.cc"
+
/* MIR2LIR dispatcher and architectural independent codegen routines */
#include "../../MethodCodegenDriver.cc"