summaryrefslogtreecommitdiff
path: root/src/compiler/codegen/MethodBitcode.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/codegen/MethodBitcode.cc')
-rw-r--r--src/compiler/codegen/MethodBitcode.cc1674
1 files changed, 1674 insertions, 0 deletions
diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc
new file mode 100644
index 0000000000..27e7d261ee
--- /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