summaryrefslogtreecommitdiffstats
path: root/compiler/dex/portable/mir_to_gbc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dex/portable/mir_to_gbc.cc')
-rw-r--r--compiler/dex/portable/mir_to_gbc.cc2056
1 files changed, 2056 insertions, 0 deletions
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
new file mode 100644
index 0000000..2be1ef4
--- /dev/null
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -0,0 +1,2056 @@
+/*
+ * 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.
+ */
+
+#include "object_utils.h"
+
+#include <llvm/ADT/DepthFirstIterator.h>
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/IR/Instruction.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Metadata.h>
+#include <llvm/IR/Type.h>
+#include <llvm/Support/Casting.h>
+#include <llvm/Support/InstIterator.h>
+#include <llvm/Support/ToolOutputFile.h>
+
+#include "dex/compiler_internals.h"
+#include "dex/dataflow_iterator-inl.h"
+#include "dex/frontend.h"
+#include "mir_to_gbc.h"
+
+#include "llvm/llvm_compilation_unit.h"
+#include "llvm/utils_llvm.h"
+
+const char* kLabelFormat = "%c0x%x_%d";
+const char kInvalidBlock = 0xff;
+const char kNormalBlock = 'L';
+const char kCatchBlock = 'C';
+
+namespace art {
+
+::llvm::BasicBlock* MirConverter::GetLLVMBlock(int id)
+{
+ return id_to_block_map_.Get(id);
+}
+
+::llvm::Value* MirConverter::GetLLVMValue(int s_reg)
+{
+ return llvm_values_.Get(s_reg);
+}
+
+void MirConverter::SetVregOnValue(::llvm::Value* val, int s_reg)
+{
+ // Set vreg for debugging
+ art::llvm::IntrinsicHelper::IntrinsicId id = art::llvm::IntrinsicHelper::SetVReg;
+ ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(id);
+ int v_reg = mir_graph_->SRegToVReg(s_reg);
+ ::llvm::Value* table_slot = irb_->getInt32(v_reg);
+ ::llvm::Value* args[] = { table_slot, val };
+ irb_->CreateCall(func, args);
+}
+
+// Replace the placeholder value with the real definition
+void MirConverter::DefineValueOnly(::llvm::Value* val, int s_reg)
+{
+ ::llvm::Value* placeholder = GetLLVMValue(s_reg);
+ if (placeholder == NULL) {
+ // This can happen on instruction rewrite on verification failure
+ LOG(WARNING) << "Null placeholder";
+ return;
+ }
+ placeholder->replaceAllUsesWith(val);
+ val->takeName(placeholder);
+ llvm_values_.Put(s_reg, val);
+ ::llvm::Instruction* inst = ::llvm::dyn_cast< ::llvm::Instruction>(placeholder);
+ DCHECK(inst != NULL);
+ inst->eraseFromParent();
+
+}
+
+void MirConverter::DefineValue(::llvm::Value* val, int s_reg)
+{
+ DefineValueOnly(val, s_reg);
+ SetVregOnValue(val, s_reg);
+}
+
+::llvm::Type* MirConverter::LlvmTypeFromLocRec(RegLocation loc)
+{
+ ::llvm::Type* res = NULL;
+ if (loc.wide) {
+ if (loc.fp)
+ res = irb_->getDoubleTy();
+ else
+ res = irb_->getInt64Ty();
+ } else {
+ if (loc.fp) {
+ res = irb_->getFloatTy();
+ } else {
+ if (loc.ref)
+ res = irb_->getJObjectTy();
+ else
+ res = irb_->getInt32Ty();
+ }
+ }
+ return res;
+}
+
+void MirConverter::InitIR()
+{
+ if (llvm_info_ == NULL) {
+ CompilerTls* tls = cu_->compiler_driver->GetTls();
+ CHECK(tls != NULL);
+ llvm_info_ = static_cast<LLVMInfo*>(tls->GetLLVMInfo());
+ if (llvm_info_ == NULL) {
+ llvm_info_ = new LLVMInfo();
+ tls->SetLLVMInfo(llvm_info_);
+ }
+ }
+ context_ = llvm_info_->GetLLVMContext();
+ module_ = llvm_info_->GetLLVMModule();
+ intrinsic_helper_ = llvm_info_->GetIntrinsicHelper();
+ irb_ = llvm_info_->GetIRBuilder();
+}
+
+::llvm::BasicBlock* MirConverter::FindCaseTarget(uint32_t vaddr)
+{
+ BasicBlock* bb = mir_graph_->FindBlock(vaddr);
+ DCHECK(bb != NULL);
+ return GetLLVMBlock(bb->id);
+}
+
+void MirConverter::ConvertPackedSwitch(BasicBlock* bb,
+ int32_t table_offset, RegLocation rl_src)
+{
+ const Instruction::PackedSwitchPayload* payload =
+ reinterpret_cast<const Instruction::PackedSwitchPayload*>(
+ cu_->insns + current_dalvik_offset_ + table_offset);
+
+ ::llvm::Value* value = GetLLVMValue(rl_src.orig_sreg);
+
+ ::llvm::SwitchInst* sw =
+ irb_->CreateSwitch(value, GetLLVMBlock(bb->fall_through->id),
+ payload->case_count);
+
+ for (uint16_t i = 0; i < payload->case_count; ++i) {
+ ::llvm::BasicBlock* llvm_bb =
+ FindCaseTarget(current_dalvik_offset_ + payload->targets[i]);
+ sw->addCase(irb_->getInt32(payload->first_key + i), llvm_bb);
+ }
+ ::llvm::MDNode* switch_node =
+ ::llvm::MDNode::get(*context_, irb_->getInt32(table_offset));
+ sw->setMetadata("SwitchTable", switch_node);
+ bb->taken = NULL;
+ bb->fall_through = NULL;
+}
+
+void MirConverter::ConvertSparseSwitch(BasicBlock* bb,
+ int32_t table_offset, RegLocation rl_src)
+{
+ const Instruction::SparseSwitchPayload* payload =
+ reinterpret_cast<const Instruction::SparseSwitchPayload*>(
+ cu_->insns + current_dalvik_offset_ + table_offset);
+
+ const int32_t* keys = payload->GetKeys();
+ const int32_t* targets = payload->GetTargets();
+
+ ::llvm::Value* value = GetLLVMValue(rl_src.orig_sreg);
+
+ ::llvm::SwitchInst* sw =
+ irb_->CreateSwitch(value, GetLLVMBlock(bb->fall_through->id),
+ payload->case_count);
+
+ for (size_t i = 0; i < payload->case_count; ++i) {
+ ::llvm::BasicBlock* llvm_bb =
+ FindCaseTarget(current_dalvik_offset_ + targets[i]);
+ sw->addCase(irb_->getInt32(keys[i]), llvm_bb);
+ }
+ ::llvm::MDNode* switch_node =
+ ::llvm::MDNode::get(*context_, irb_->getInt32(table_offset));
+ sw->setMetadata("SwitchTable", switch_node);
+ bb->taken = NULL;
+ bb->fall_through = NULL;
+}
+
+void MirConverter::ConvertSget(int32_t field_index,
+ art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_dest)
+{
+ ::llvm::Constant* field_idx = irb_->getInt32(field_index);
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Value* res = irb_->CreateCall(intr, field_idx);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertSput(int32_t field_index,
+ art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_src)
+{
+ ::llvm::SmallVector< ::llvm::Value*, 2> args;
+ args.push_back(irb_->getInt32(field_index));
+ args.push_back(GetLLVMValue(rl_src.orig_sreg));
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ irb_->CreateCall(intr, args);
+}
+
+void MirConverter::ConvertFillArrayData(int32_t offset, RegLocation rl_array)
+{
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ id = art::llvm::IntrinsicHelper::HLFillArrayData;
+ ::llvm::SmallVector< ::llvm::Value*, 2> args;
+ args.push_back(irb_->getInt32(offset));
+ args.push_back(GetLLVMValue(rl_array.orig_sreg));
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ irb_->CreateCall(intr, args);
+}
+
+::llvm::Value* MirConverter::EmitConst(::llvm::ArrayRef< ::llvm::Value*> src,
+ RegLocation loc)
+{
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ if (loc.wide) {
+ if (loc.fp) {
+ id = art::llvm::IntrinsicHelper::ConstDouble;
+ } else {
+ id = art::llvm::IntrinsicHelper::ConstLong;
+ }
+ } else {
+ if (loc.fp) {
+ id = art::llvm::IntrinsicHelper::ConstFloat;
+ } else if (loc.ref) {
+ id = art::llvm::IntrinsicHelper::ConstObj;
+ } else {
+ id = art::llvm::IntrinsicHelper::ConstInt;
+ }
+ }
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ return irb_->CreateCall(intr, src);
+}
+
+void MirConverter::EmitPopShadowFrame()
+{
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(
+ art::llvm::IntrinsicHelper::PopShadowFrame);
+ irb_->CreateCall(intr);
+}
+
+::llvm::Value* MirConverter::EmitCopy(::llvm::ArrayRef< ::llvm::Value*> src,
+ RegLocation loc)
+{
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ if (loc.wide) {
+ if (loc.fp) {
+ id = art::llvm::IntrinsicHelper::CopyDouble;
+ } else {
+ id = art::llvm::IntrinsicHelper::CopyLong;
+ }
+ } else {
+ if (loc.fp) {
+ id = art::llvm::IntrinsicHelper::CopyFloat;
+ } else if (loc.ref) {
+ id = art::llvm::IntrinsicHelper::CopyObj;
+ } else {
+ id = art::llvm::IntrinsicHelper::CopyInt;
+ }
+ }
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ return irb_->CreateCall(intr, src);
+}
+
+void MirConverter::ConvertMoveException(RegLocation rl_dest)
+{
+ ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(
+ art::llvm::IntrinsicHelper::GetException);
+ ::llvm::Value* res = irb_->CreateCall(func);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertThrow(RegLocation rl_src)
+{
+ ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
+ ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(
+ art::llvm::IntrinsicHelper::HLThrowException);
+ irb_->CreateCall(func, src);
+}
+
+void MirConverter::ConvertMonitorEnterExit(int opt_flags,
+ art::llvm::IntrinsicHelper::IntrinsicId id,
+ RegLocation rl_src)
+{
+ ::llvm::SmallVector< ::llvm::Value*, 2> args;
+ args.push_back(irb_->getInt32(opt_flags));
+ args.push_back(GetLLVMValue(rl_src.orig_sreg));
+ ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(id);
+ irb_->CreateCall(func, args);
+}
+
+void MirConverter::ConvertArrayLength(int opt_flags,
+ RegLocation rl_dest, RegLocation rl_src)
+{
+ ::llvm::SmallVector< ::llvm::Value*, 2> args;
+ args.push_back(irb_->getInt32(opt_flags));
+ args.push_back(GetLLVMValue(rl_src.orig_sreg));
+ ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(
+ art::llvm::IntrinsicHelper::OptArrayLength);
+ ::llvm::Value* res = irb_->CreateCall(func, args);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::EmitSuspendCheck()
+{
+ art::llvm::IntrinsicHelper::IntrinsicId id =
+ art::llvm::IntrinsicHelper::CheckSuspend;
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ irb_->CreateCall(intr);
+}
+
+::llvm::Value* MirConverter::ConvertCompare(ConditionCode cc,
+ ::llvm::Value* src1, ::llvm::Value* src2)
+{
+ ::llvm::Value* res = NULL;
+ DCHECK_EQ(src1->getType(), src2->getType());
+ switch(cc) {
+ case kCondEq: res = irb_->CreateICmpEQ(src1, src2); break;
+ case kCondNe: res = irb_->CreateICmpNE(src1, src2); break;
+ case kCondLt: res = irb_->CreateICmpSLT(src1, src2); break;
+ case kCondGe: res = irb_->CreateICmpSGE(src1, src2); break;
+ case kCondGt: res = irb_->CreateICmpSGT(src1, src2); break;
+ case kCondLe: res = irb_->CreateICmpSLE(src1, src2); break;
+ default: LOG(FATAL) << "Unexpected cc value " << cc;
+ }
+ return res;
+}
+
+void MirConverter::ConvertCompareAndBranch(BasicBlock* bb, MIR* mir,
+ ConditionCode cc, RegLocation rl_src1, RegLocation rl_src2)
+{
+ if (bb->taken->start_offset <= mir->offset) {
+ EmitSuspendCheck();
+ }
+ ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
+ ::llvm::Value* src2 = GetLLVMValue(rl_src2.orig_sreg);
+ ::llvm::Value* cond_value = ConvertCompare(cc, src1, src2);
+ cond_value->setName(StringPrintf("t%d", temp_name_++));
+ irb_->CreateCondBr(cond_value, GetLLVMBlock(bb->taken->id),
+ GetLLVMBlock(bb->fall_through->id));
+ // Don't redo the fallthrough branch in the BB driver
+ bb->fall_through = NULL;
+}
+
+void MirConverter::ConvertCompareZeroAndBranch(BasicBlock* bb,
+ MIR* mir, ConditionCode cc, RegLocation rl_src1)
+{
+ if (bb->taken->start_offset <= mir->offset) {
+ EmitSuspendCheck();
+ }
+ ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
+ ::llvm::Value* src2;
+ if (rl_src1.ref) {
+ src2 = irb_->getJNull();
+ } else {
+ src2 = irb_->getInt32(0);
+ }
+ ::llvm::Value* cond_value = ConvertCompare(cc, src1, src2);
+ irb_->CreateCondBr(cond_value, GetLLVMBlock(bb->taken->id),
+ GetLLVMBlock(bb->fall_through->id));
+ // Don't redo the fallthrough branch in the BB driver
+ bb->fall_through = NULL;
+}
+
+::llvm::Value* MirConverter::GenDivModOp(bool is_div, bool is_long,
+ ::llvm::Value* src1, ::llvm::Value* src2)
+{
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ if (is_long) {
+ if (is_div) {
+ id = art::llvm::IntrinsicHelper::DivLong;
+ } else {
+ id = art::llvm::IntrinsicHelper::RemLong;
+ }
+ } else {
+ if (is_div) {
+ id = art::llvm::IntrinsicHelper::DivInt;
+ } else {
+ id = art::llvm::IntrinsicHelper::RemInt;
+ }
+ }
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::SmallVector< ::llvm::Value*, 2>args;
+ args.push_back(src1);
+ args.push_back(src2);
+ return irb_->CreateCall(intr, args);
+}
+
+::llvm::Value* MirConverter::GenArithOp(OpKind op, bool is_long,
+ ::llvm::Value* src1, ::llvm::Value* src2)
+{
+ ::llvm::Value* res = NULL;
+ switch(op) {
+ case kOpAdd: res = irb_->CreateAdd(src1, src2); break;
+ case kOpSub: res = irb_->CreateSub(src1, src2); break;
+ case kOpRsub: res = irb_->CreateSub(src2, src1); break;
+ case kOpMul: res = irb_->CreateMul(src1, src2); break;
+ case kOpOr: res = irb_->CreateOr(src1, src2); break;
+ case kOpAnd: res = irb_->CreateAnd(src1, src2); break;
+ case kOpXor: res = irb_->CreateXor(src1, src2); break;
+ case kOpDiv: res = GenDivModOp(true, is_long, src1, src2); break;
+ case kOpRem: res = GenDivModOp(false, is_long, src1, src2); break;
+ case kOpLsl: res = irb_->CreateShl(src1, src2); break;
+ case kOpLsr: res = irb_->CreateLShr(src1, src2); break;
+ case kOpAsr: res = irb_->CreateAShr(src1, src2); break;
+ default:
+ LOG(FATAL) << "Invalid op " << op;
+ }
+ return res;
+}
+
+void MirConverter::ConvertFPArithOp(OpKind op, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2)
+{
+ ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
+ ::llvm::Value* src2 = GetLLVMValue(rl_src2.orig_sreg);
+ ::llvm::Value* res = NULL;
+ switch(op) {
+ case kOpAdd: res = irb_->CreateFAdd(src1, src2); break;
+ case kOpSub: res = irb_->CreateFSub(src1, src2); break;
+ case kOpMul: res = irb_->CreateFMul(src1, src2); break;
+ case kOpDiv: res = irb_->CreateFDiv(src1, src2); break;
+ case kOpRem: res = irb_->CreateFRem(src1, src2); break;
+ default:
+ LOG(FATAL) << "Invalid op " << op;
+ }
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertShift(art::llvm::IntrinsicHelper::IntrinsicId id,
+ RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
+{
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::SmallVector< ::llvm::Value*, 2>args;
+ args.push_back(GetLLVMValue(rl_src1.orig_sreg));
+ args.push_back(GetLLVMValue(rl_src2.orig_sreg));
+ ::llvm::Value* res = irb_->CreateCall(intr, args);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertShiftLit(art::llvm::IntrinsicHelper::IntrinsicId id,
+ RegLocation rl_dest, RegLocation rl_src, int shift_amount)
+{
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::SmallVector< ::llvm::Value*, 2>args;
+ args.push_back(GetLLVMValue(rl_src.orig_sreg));
+ args.push_back(irb_->getInt32(shift_amount));
+ ::llvm::Value* res = irb_->CreateCall(intr, args);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertArithOp(OpKind op, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2)
+{
+ ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
+ ::llvm::Value* src2 = GetLLVMValue(rl_src2.orig_sreg);
+ DCHECK_EQ(src1->getType(), src2->getType());
+ ::llvm::Value* res = GenArithOp(op, rl_dest.wide, src1, src2);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertArithOpLit(OpKind op, RegLocation rl_dest,
+ RegLocation rl_src1, int32_t imm)
+{
+ ::llvm::Value* src1 = GetLLVMValue(rl_src1.orig_sreg);
+ ::llvm::Value* src2 = irb_->getInt32(imm);
+ ::llvm::Value* res = GenArithOp(op, rl_dest.wide, src1, src2);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+/*
+ * Process arguments for invoke. Note: this code is also used to
+ * collect and process arguments for NEW_FILLED_ARRAY and NEW_FILLED_ARRAY_RANGE.
+ * The requirements are similar.
+ */
+void MirConverter::ConvertInvoke(BasicBlock* bb, MIR* mir,
+ InvokeType invoke_type, bool is_range, bool is_filled_new_array)
+{
+ CallInfo* info = mir_graph_->NewMemCallInfo(bb, mir, invoke_type, is_range);
+ ::llvm::SmallVector< ::llvm::Value*, 10> args;
+ // Insert the invoke_type
+ args.push_back(irb_->getInt32(static_cast<int>(invoke_type)));
+ // Insert the method_idx
+ args.push_back(irb_->getInt32(info->index));
+ // Insert the optimization flags
+ args.push_back(irb_->getInt32(info->opt_flags));
+ // Now, insert the actual arguments
+ for (int i = 0; i < info->num_arg_words;) {
+ ::llvm::Value* val = GetLLVMValue(info->args[i].orig_sreg);
+ args.push_back(val);
+ i += info->args[i].wide ? 2 : 1;
+ }
+ /*
+ * Choose the invoke return type based on actual usage. Note: may
+ * be different than shorty. For example, if a function return value
+ * is not used, we'll treat this as a void invoke.
+ */
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ if (is_filled_new_array) {
+ id = art::llvm::IntrinsicHelper::HLFilledNewArray;
+ } else if (info->result.location == kLocInvalid) {
+ id = art::llvm::IntrinsicHelper::HLInvokeVoid;
+ } else {
+ if (info->result.wide) {
+ if (info->result.fp) {
+ id = art::llvm::IntrinsicHelper::HLInvokeDouble;
+ } else {
+ id = art::llvm::IntrinsicHelper::HLInvokeLong;
+ }
+ } else if (info->result.ref) {
+ id = art::llvm::IntrinsicHelper::HLInvokeObj;
+ } else if (info->result.fp) {
+ id = art::llvm::IntrinsicHelper::HLInvokeFloat;
+ } else {
+ id = art::llvm::IntrinsicHelper::HLInvokeInt;
+ }
+ }
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Value* res = irb_->CreateCall(intr, args);
+ if (info->result.location != kLocInvalid) {
+ DefineValue(res, info->result.orig_sreg);
+ }
+}
+
+void MirConverter::ConvertConstObject(uint32_t idx,
+ art::llvm::IntrinsicHelper::IntrinsicId id, RegLocation rl_dest)
+{
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Value* index = irb_->getInt32(idx);
+ ::llvm::Value* res = irb_->CreateCall(intr, index);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertCheckCast(uint32_t type_idx, RegLocation rl_src)
+{
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ id = art::llvm::IntrinsicHelper::HLCheckCast;
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::SmallVector< ::llvm::Value*, 2> args;
+ args.push_back(irb_->getInt32(type_idx));
+ args.push_back(GetLLVMValue(rl_src.orig_sreg));
+ irb_->CreateCall(intr, args);
+}
+
+void MirConverter::ConvertNewInstance(uint32_t type_idx, RegLocation rl_dest)
+{
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ id = art::llvm::IntrinsicHelper::NewInstance;
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Value* index = irb_->getInt32(type_idx);
+ ::llvm::Value* res = irb_->CreateCall(intr, index);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertNewArray(uint32_t type_idx,
+ RegLocation rl_dest, RegLocation rl_src)
+{
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ id = art::llvm::IntrinsicHelper::NewArray;
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::SmallVector< ::llvm::Value*, 2> args;
+ args.push_back(irb_->getInt32(type_idx));
+ args.push_back(GetLLVMValue(rl_src.orig_sreg));
+ ::llvm::Value* res = irb_->CreateCall(intr, args);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertAget(int opt_flags,
+ art::llvm::IntrinsicHelper::IntrinsicId id,
+ RegLocation rl_dest, RegLocation rl_array, RegLocation rl_index)
+{
+ ::llvm::SmallVector< ::llvm::Value*, 3> args;
+ args.push_back(irb_->getInt32(opt_flags));
+ args.push_back(GetLLVMValue(rl_array.orig_sreg));
+ args.push_back(GetLLVMValue(rl_index.orig_sreg));
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Value* res = irb_->CreateCall(intr, args);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertAput(int opt_flags,
+ art::llvm::IntrinsicHelper::IntrinsicId id,
+ RegLocation rl_src, RegLocation rl_array, RegLocation rl_index)
+{
+ ::llvm::SmallVector< ::llvm::Value*, 4> args;
+ args.push_back(irb_->getInt32(opt_flags));
+ args.push_back(GetLLVMValue(rl_src.orig_sreg));
+ args.push_back(GetLLVMValue(rl_array.orig_sreg));
+ args.push_back(GetLLVMValue(rl_index.orig_sreg));
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ irb_->CreateCall(intr, args);
+}
+
+void MirConverter::ConvertIget(int opt_flags,
+ art::llvm::IntrinsicHelper::IntrinsicId id,
+ RegLocation rl_dest, RegLocation rl_obj, int field_index)
+{
+ ::llvm::SmallVector< ::llvm::Value*, 3> args;
+ args.push_back(irb_->getInt32(opt_flags));
+ args.push_back(GetLLVMValue(rl_obj.orig_sreg));
+ args.push_back(irb_->getInt32(field_index));
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Value* res = irb_->CreateCall(intr, args);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertIput(int opt_flags,
+ art::llvm::IntrinsicHelper::IntrinsicId id,
+ RegLocation rl_src, RegLocation rl_obj, int field_index)
+{
+ ::llvm::SmallVector< ::llvm::Value*, 4> args;
+ args.push_back(irb_->getInt32(opt_flags));
+ args.push_back(GetLLVMValue(rl_src.orig_sreg));
+ args.push_back(GetLLVMValue(rl_obj.orig_sreg));
+ args.push_back(irb_->getInt32(field_index));
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ irb_->CreateCall(intr, args);
+}
+
+void MirConverter::ConvertInstanceOf(uint32_t type_idx,
+ RegLocation rl_dest, RegLocation rl_src)
+{
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ id = art::llvm::IntrinsicHelper::InstanceOf;
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::SmallVector< ::llvm::Value*, 2> args;
+ args.push_back(irb_->getInt32(type_idx));
+ args.push_back(GetLLVMValue(rl_src.orig_sreg));
+ ::llvm::Value* res = irb_->CreateCall(intr, args);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertIntToLong(RegLocation rl_dest, RegLocation rl_src)
+{
+ ::llvm::Value* res = irb_->CreateSExt(GetLLVMValue(rl_src.orig_sreg),
+ irb_->getInt64Ty());
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertLongToInt(RegLocation rl_dest, RegLocation rl_src)
+{
+ ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
+ ::llvm::Value* res = irb_->CreateTrunc(src, irb_->getInt32Ty());
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertFloatToDouble(RegLocation rl_dest, RegLocation rl_src)
+{
+ ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
+ ::llvm::Value* res = irb_->CreateFPExt(src, irb_->getDoubleTy());
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertDoubleToFloat(RegLocation rl_dest, RegLocation rl_src)
+{
+ ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
+ ::llvm::Value* res = irb_->CreateFPTrunc(src, irb_->getFloatTy());
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertWideComparison(art::llvm::IntrinsicHelper::IntrinsicId id,
+ RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2)
+{
+ DCHECK_EQ(rl_src1.fp, rl_src2.fp);
+ DCHECK_EQ(rl_src1.wide, rl_src2.wide);
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::SmallVector< ::llvm::Value*, 2> args;
+ args.push_back(GetLLVMValue(rl_src1.orig_sreg));
+ args.push_back(GetLLVMValue(rl_src2.orig_sreg));
+ ::llvm::Value* res = irb_->CreateCall(intr, args);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertIntNarrowing(RegLocation rl_dest, RegLocation rl_src,
+ art::llvm::IntrinsicHelper::IntrinsicId id)
+{
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Value* res =
+ irb_->CreateCall(intr, GetLLVMValue(rl_src.orig_sreg));
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertNeg(RegLocation rl_dest, RegLocation rl_src)
+{
+ ::llvm::Value* res = irb_->CreateNeg(GetLLVMValue(rl_src.orig_sreg));
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertIntToFP(::llvm::Type* ty, RegLocation rl_dest,
+ RegLocation rl_src)
+{
+ ::llvm::Value* res =
+ irb_->CreateSIToFP(GetLLVMValue(rl_src.orig_sreg), ty);
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertFPToInt(art::llvm::IntrinsicHelper::IntrinsicId id,
+ RegLocation rl_dest,
+ RegLocation rl_src)
+{
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Value* res = irb_->CreateCall(intr, GetLLVMValue(rl_src.orig_sreg));
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+
+void MirConverter::ConvertNegFP(RegLocation rl_dest, RegLocation rl_src)
+{
+ ::llvm::Value* res =
+ irb_->CreateFNeg(GetLLVMValue(rl_src.orig_sreg));
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::ConvertNot(RegLocation rl_dest, RegLocation rl_src)
+{
+ ::llvm::Value* src = GetLLVMValue(rl_src.orig_sreg);
+ ::llvm::Value* res = irb_->CreateXor(src, static_cast<uint64_t>(-1));
+ DefineValue(res, rl_dest.orig_sreg);
+}
+
+void MirConverter::EmitConstructorBarrier() {
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(
+ art::llvm::IntrinsicHelper::ConstructorBarrier);
+ irb_->CreateCall(intr);
+}
+
+/*
+ * Target-independent code generation. Use only high-level
+ * load/store utilities here, or target-dependent genXX() handlers
+ * when necessary.
+ */
+bool MirConverter::ConvertMIRNode(MIR* mir, BasicBlock* bb,
+ ::llvm::BasicBlock* llvm_bb)
+{
+ bool res = false; // Assume success
+ RegLocation rl_src[3];
+ RegLocation rl_dest = mir_graph_->GetBadLoc();
+ Instruction::Code opcode = mir->dalvikInsn.opcode;
+ int op_val = opcode;
+ uint32_t vB = mir->dalvikInsn.vB;
+ uint32_t vC = mir->dalvikInsn.vC;
+ int opt_flags = mir->optimization_flags;
+
+ if (cu_->verbose) {
+ if (op_val < kMirOpFirst) {
+ LOG(INFO) << ".. " << Instruction::Name(opcode) << " 0x" << std::hex << op_val;
+ } else {
+ LOG(INFO) << mir_graph_->extended_mir_op_names_[op_val - kMirOpFirst] << " 0x" << std::hex << op_val;
+ }
+ }
+
+ /* Prep Src and Dest locations */
+ int next_sreg = 0;
+ int next_loc = 0;
+ int attrs = mir_graph_->oat_data_flow_attributes_[opcode];
+ rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc();
+ if (attrs & DF_UA) {
+ if (attrs & DF_A_WIDE) {
+ rl_src[next_loc++] = mir_graph_->GetSrcWide(mir, next_sreg);
+ next_sreg+= 2;
+ } else {
+ rl_src[next_loc++] = mir_graph_->GetSrc(mir, next_sreg);
+ next_sreg++;
+ }
+ }
+ if (attrs & DF_UB) {
+ if (attrs & DF_B_WIDE) {
+ rl_src[next_loc++] = mir_graph_->GetSrcWide(mir, next_sreg);
+ next_sreg+= 2;
+ } else {
+ rl_src[next_loc++] = mir_graph_->GetSrc(mir, next_sreg);
+ next_sreg++;
+ }
+ }
+ if (attrs & DF_UC) {
+ if (attrs & DF_C_WIDE) {
+ rl_src[next_loc++] = mir_graph_->GetSrcWide(mir, next_sreg);
+ } else {
+ rl_src[next_loc++] = mir_graph_->GetSrc(mir, next_sreg);
+ }
+ }
+ if (attrs & DF_DA) {
+ if (attrs & DF_A_WIDE) {
+ rl_dest = mir_graph_->GetDestWide(mir);
+ } else {
+ rl_dest = mir_graph_->GetDest(mir);
+ }
+ }
+
+ 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_OBJECT_FROM16:
+ 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(rl_src[0].orig_sreg);
+ ::llvm::Value* res = EmitCopy(src, rl_dest);
+ DefineValue(res, rl_dest.orig_sreg);
+ }
+ break;
+
+ case Instruction::CONST:
+ case Instruction::CONST_4:
+ case Instruction::CONST_16: {
+ ::llvm::Constant* imm_value = irb_->getJInt(vB);
+ ::llvm::Value* res = EmitConst(imm_value, rl_dest);
+ DefineValue(res, rl_dest.orig_sreg);
+ }
+ break;
+
+ case Instruction::CONST_WIDE_16:
+ case Instruction::CONST_WIDE_32: {
+ // Sign extend to 64 bits
+ int64_t imm = static_cast<int32_t>(vB);
+ ::llvm::Constant* imm_value = irb_->getJLong(imm);
+ ::llvm::Value* res = EmitConst(imm_value, rl_dest);
+ DefineValue(res, rl_dest.orig_sreg);
+ }
+ break;
+
+ case Instruction::CONST_HIGH16: {
+ ::llvm::Constant* imm_value = irb_->getJInt(vB << 16);
+ ::llvm::Value* res = EmitConst(imm_value, rl_dest);
+ DefineValue(res, rl_dest.orig_sreg);
+ }
+ break;
+
+ case Instruction::CONST_WIDE: {
+ ::llvm::Constant* imm_value =
+ irb_->getJLong(mir->dalvikInsn.vB_wide);
+ ::llvm::Value* res = EmitConst(imm_value, rl_dest);
+ DefineValue(res, rl_dest.orig_sreg);
+ }
+ break;
+ case Instruction::CONST_WIDE_HIGH16: {
+ int64_t imm = static_cast<int64_t>(vB) << 48;
+ ::llvm::Constant* imm_value = irb_->getJLong(imm);
+ ::llvm::Value* res = EmitConst(imm_value, rl_dest);
+ DefineValue(res, rl_dest.orig_sreg);
+ }
+ break;
+
+ case Instruction::SPUT_OBJECT:
+ ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputObject,
+ rl_src[0]);
+ break;
+ case Instruction::SPUT:
+ if (rl_src[0].fp) {
+ ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputFloat,
+ rl_src[0]);
+ } else {
+ ConvertSput(vB, art::llvm::IntrinsicHelper::HLSput, rl_src[0]);
+ }
+ break;
+ case Instruction::SPUT_BOOLEAN:
+ ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputBoolean,
+ rl_src[0]);
+ break;
+ case Instruction::SPUT_BYTE:
+ ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputByte, rl_src[0]);
+ break;
+ case Instruction::SPUT_CHAR:
+ ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputChar, rl_src[0]);
+ break;
+ case Instruction::SPUT_SHORT:
+ ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputShort, rl_src[0]);
+ break;
+ case Instruction::SPUT_WIDE:
+ if (rl_src[0].fp) {
+ ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputDouble,
+ rl_src[0]);
+ } else {
+ ConvertSput(vB, art::llvm::IntrinsicHelper::HLSputWide,
+ rl_src[0]);
+ }
+ break;
+
+ case Instruction::SGET_OBJECT:
+ ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetObject, rl_dest);
+ break;
+ case Instruction::SGET:
+ if (rl_dest.fp) {
+ ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetFloat, rl_dest);
+ } else {
+ ConvertSget(vB, art::llvm::IntrinsicHelper::HLSget, rl_dest);
+ }
+ break;
+ case Instruction::SGET_BOOLEAN:
+ ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetBoolean, rl_dest);
+ break;
+ case Instruction::SGET_BYTE:
+ ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetByte, rl_dest);
+ break;
+ case Instruction::SGET_CHAR:
+ ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetChar, rl_dest);
+ break;
+ case Instruction::SGET_SHORT:
+ ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetShort, rl_dest);
+ break;
+ case Instruction::SGET_WIDE:
+ if (rl_dest.fp) {
+ ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetDouble,
+ rl_dest);
+ } else {
+ ConvertSget(vB, art::llvm::IntrinsicHelper::HLSgetWide, rl_dest);
+ }
+ break;
+
+ case Instruction::RETURN_WIDE:
+ case Instruction::RETURN:
+ case Instruction::RETURN_OBJECT: {
+ if (!mir_graph_->MethodIsLeaf()) {
+ EmitSuspendCheck();
+ }
+ EmitPopShadowFrame();
+ irb_->CreateRet(GetLLVMValue(rl_src[0].orig_sreg));
+ DCHECK(bb->terminated_by_return);
+ }
+ break;
+
+ case Instruction::RETURN_VOID: {
+ if (((cu_->access_flags & kAccConstructor) != 0) &&
+ cu_->compiler_driver->RequiresConstructorBarrier(Thread::Current(),
+ cu_->dex_file,
+ cu_->class_def_idx)) {
+ EmitConstructorBarrier();
+ }
+ if (!mir_graph_->MethodIsLeaf()) {
+ EmitSuspendCheck();
+ }
+ EmitPopShadowFrame();
+ irb_->CreateRetVoid();
+ DCHECK(bb->terminated_by_return);
+ }
+ break;
+
+ case Instruction::IF_EQ:
+ ConvertCompareAndBranch(bb, mir, kCondEq, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::IF_NE:
+ ConvertCompareAndBranch(bb, mir, kCondNe, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::IF_LT:
+ ConvertCompareAndBranch(bb, mir, kCondLt, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::IF_GE:
+ ConvertCompareAndBranch(bb, mir, kCondGe, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::IF_GT:
+ ConvertCompareAndBranch(bb, mir, kCondGt, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::IF_LE:
+ ConvertCompareAndBranch(bb, mir, kCondLe, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::IF_EQZ:
+ ConvertCompareZeroAndBranch(bb, mir, kCondEq, rl_src[0]);
+ break;
+ case Instruction::IF_NEZ:
+ ConvertCompareZeroAndBranch(bb, mir, kCondNe, rl_src[0]);
+ break;
+ case Instruction::IF_LTZ:
+ ConvertCompareZeroAndBranch(bb, mir, kCondLt, rl_src[0]);
+ break;
+ case Instruction::IF_GEZ:
+ ConvertCompareZeroAndBranch(bb, mir, kCondGe, rl_src[0]);
+ break;
+ case Instruction::IF_GTZ:
+ ConvertCompareZeroAndBranch(bb, mir, kCondGt, rl_src[0]);
+ break;
+ case Instruction::IF_LEZ:
+ ConvertCompareZeroAndBranch(bb, mir, kCondLe, rl_src[0]);
+ break;
+
+ case Instruction::GOTO:
+ case Instruction::GOTO_16:
+ case Instruction::GOTO_32: {
+ if (bb->taken->start_offset <= bb->start_offset) {
+ EmitSuspendCheck();
+ }
+ irb_->CreateBr(GetLLVMBlock(bb->taken->id));
+ }
+ break;
+
+ case Instruction::ADD_LONG:
+ case Instruction::ADD_LONG_2ADDR:
+ case Instruction::ADD_INT:
+ case Instruction::ADD_INT_2ADDR:
+ ConvertArithOp(kOpAdd, rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::SUB_LONG:
+ case Instruction::SUB_LONG_2ADDR:
+ case Instruction::SUB_INT:
+ case Instruction::SUB_INT_2ADDR:
+ ConvertArithOp(kOpSub, rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::MUL_LONG:
+ case Instruction::MUL_LONG_2ADDR:
+ case Instruction::MUL_INT:
+ case Instruction::MUL_INT_2ADDR:
+ ConvertArithOp(kOpMul, rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::DIV_LONG:
+ case Instruction::DIV_LONG_2ADDR:
+ case Instruction::DIV_INT:
+ case Instruction::DIV_INT_2ADDR:
+ ConvertArithOp(kOpDiv, rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::REM_LONG:
+ case Instruction::REM_LONG_2ADDR:
+ case Instruction::REM_INT:
+ case Instruction::REM_INT_2ADDR:
+ ConvertArithOp(kOpRem, rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::AND_LONG:
+ case Instruction::AND_LONG_2ADDR:
+ case Instruction::AND_INT:
+ case Instruction::AND_INT_2ADDR:
+ ConvertArithOp(kOpAnd, rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::OR_LONG:
+ case Instruction::OR_LONG_2ADDR:
+ case Instruction::OR_INT:
+ case Instruction::OR_INT_2ADDR:
+ ConvertArithOp(kOpOr, rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::XOR_LONG:
+ case Instruction::XOR_LONG_2ADDR:
+ case Instruction::XOR_INT:
+ case Instruction::XOR_INT_2ADDR:
+ ConvertArithOp(kOpXor, rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::SHL_LONG:
+ case Instruction::SHL_LONG_2ADDR:
+ ConvertShift(art::llvm::IntrinsicHelper::SHLLong,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::SHL_INT:
+ case Instruction::SHL_INT_2ADDR:
+ ConvertShift(art::llvm::IntrinsicHelper::SHLInt,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::SHR_LONG:
+ case Instruction::SHR_LONG_2ADDR:
+ ConvertShift(art::llvm::IntrinsicHelper::SHRLong,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::SHR_INT:
+ case Instruction::SHR_INT_2ADDR:
+ ConvertShift(art::llvm::IntrinsicHelper::SHRInt,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::USHR_LONG:
+ case Instruction::USHR_LONG_2ADDR:
+ ConvertShift(art::llvm::IntrinsicHelper::USHRLong,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::USHR_INT:
+ case Instruction::USHR_INT_2ADDR:
+ ConvertShift(art::llvm::IntrinsicHelper::USHRInt,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+
+ case Instruction::ADD_INT_LIT16:
+ case Instruction::ADD_INT_LIT8:
+ ConvertArithOpLit(kOpAdd, rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::RSUB_INT:
+ case Instruction::RSUB_INT_LIT8:
+ ConvertArithOpLit(kOpRsub, rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::MUL_INT_LIT16:
+ case Instruction::MUL_INT_LIT8:
+ ConvertArithOpLit(kOpMul, rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::DIV_INT_LIT16:
+ case Instruction::DIV_INT_LIT8:
+ ConvertArithOpLit(kOpDiv, rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::REM_INT_LIT16:
+ case Instruction::REM_INT_LIT8:
+ ConvertArithOpLit(kOpRem, rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::AND_INT_LIT16:
+ case Instruction::AND_INT_LIT8:
+ ConvertArithOpLit(kOpAnd, rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::OR_INT_LIT16:
+ case Instruction::OR_INT_LIT8:
+ ConvertArithOpLit(kOpOr, rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::XOR_INT_LIT16:
+ case Instruction::XOR_INT_LIT8:
+ ConvertArithOpLit(kOpXor, rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::SHL_INT_LIT8:
+ ConvertShiftLit(art::llvm::IntrinsicHelper::SHLInt,
+ rl_dest, rl_src[0], vC & 0x1f);
+ break;
+ case Instruction::SHR_INT_LIT8:
+ ConvertShiftLit(art::llvm::IntrinsicHelper::SHRInt,
+ rl_dest, rl_src[0], vC & 0x1f);
+ break;
+ case Instruction::USHR_INT_LIT8:
+ ConvertShiftLit(art::llvm::IntrinsicHelper::USHRInt,
+ rl_dest, rl_src[0], vC & 0x1f);
+ break;
+
+ case Instruction::ADD_FLOAT:
+ case Instruction::ADD_FLOAT_2ADDR:
+ case Instruction::ADD_DOUBLE:
+ case Instruction::ADD_DOUBLE_2ADDR:
+ ConvertFPArithOp(kOpAdd, rl_dest, rl_src[0], rl_src[1]);
+ break;
+
+ case Instruction::SUB_FLOAT:
+ case Instruction::SUB_FLOAT_2ADDR:
+ case Instruction::SUB_DOUBLE:
+ case Instruction::SUB_DOUBLE_2ADDR:
+ ConvertFPArithOp(kOpSub, rl_dest, rl_src[0], rl_src[1]);
+ break;
+
+ case Instruction::MUL_FLOAT:
+ case Instruction::MUL_FLOAT_2ADDR:
+ case Instruction::MUL_DOUBLE:
+ case Instruction::MUL_DOUBLE_2ADDR:
+ ConvertFPArithOp(kOpMul, rl_dest, rl_src[0], rl_src[1]);
+ break;
+
+ case Instruction::DIV_FLOAT:
+ case Instruction::DIV_FLOAT_2ADDR:
+ case Instruction::DIV_DOUBLE:
+ case Instruction::DIV_DOUBLE_2ADDR:
+ ConvertFPArithOp(kOpDiv, rl_dest, rl_src[0], rl_src[1]);
+ break;
+
+ case Instruction::REM_FLOAT:
+ case Instruction::REM_FLOAT_2ADDR:
+ case Instruction::REM_DOUBLE:
+ case Instruction::REM_DOUBLE_2ADDR:
+ ConvertFPArithOp(kOpRem, rl_dest, rl_src[0], rl_src[1]);
+ break;
+
+ case Instruction::INVOKE_STATIC:
+ ConvertInvoke(bb, mir, kStatic, false /*range*/,
+ false /* NewFilledArray */);
+ break;
+ case Instruction::INVOKE_STATIC_RANGE:
+ ConvertInvoke(bb, mir, kStatic, true /*range*/,
+ false /* NewFilledArray */);
+ break;
+
+ case Instruction::INVOKE_DIRECT:
+ ConvertInvoke(bb, mir, kDirect, false /*range*/,
+ false /* NewFilledArray */);
+ break;
+ case Instruction::INVOKE_DIRECT_RANGE:
+ ConvertInvoke(bb, mir, kDirect, true /*range*/,
+ false /* NewFilledArray */);
+ break;
+
+ case Instruction::INVOKE_VIRTUAL:
+ ConvertInvoke(bb, mir, kVirtual, false /*range*/,
+ false /* NewFilledArray */);
+ break;
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ ConvertInvoke(bb, mir, kVirtual, true /*range*/,
+ false /* NewFilledArray */);
+ break;
+
+ case Instruction::INVOKE_SUPER:
+ ConvertInvoke(bb, mir, kSuper, false /*range*/,
+ false /* NewFilledArray */);
+ break;
+ case Instruction::INVOKE_SUPER_RANGE:
+ ConvertInvoke(bb, mir, kSuper, true /*range*/,
+ false /* NewFilledArray */);
+ break;
+
+ case Instruction::INVOKE_INTERFACE:
+ ConvertInvoke(bb, mir, kInterface, false /*range*/,
+ false /* NewFilledArray */);
+ break;
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ ConvertInvoke(bb, mir, kInterface, true /*range*/,
+ false /* NewFilledArray */);
+ break;
+ case Instruction::FILLED_NEW_ARRAY:
+ ConvertInvoke(bb, mir, kInterface, false /*range*/,
+ true /* NewFilledArray */);
+ break;
+ case Instruction::FILLED_NEW_ARRAY_RANGE:
+ ConvertInvoke(bb, mir, kInterface, true /*range*/,
+ true /* NewFilledArray */);
+ break;
+
+ case Instruction::CONST_STRING:
+ case Instruction::CONST_STRING_JUMBO:
+ ConvertConstObject(vB, art::llvm::IntrinsicHelper::ConstString,
+ rl_dest);
+ break;
+
+ case Instruction::CONST_CLASS:
+ ConvertConstObject(vB, art::llvm::IntrinsicHelper::ConstClass,
+ rl_dest);
+ break;
+
+ case Instruction::CHECK_CAST:
+ ConvertCheckCast(vB, rl_src[0]);
+ break;
+
+ case Instruction::NEW_INSTANCE:
+ ConvertNewInstance(vB, rl_dest);
+ break;
+
+ case Instruction::MOVE_EXCEPTION:
+ ConvertMoveException(rl_dest);
+ break;
+
+ case Instruction::THROW:
+ ConvertThrow(rl_src[0]);
+ /*
+ * If this throw is standalone, terminate.
+ * If it might rethrow, force termination
+ * of the following block.
+ */
+ if (bb->fall_through == NULL) {
+ irb_->CreateUnreachable();
+ } else {
+ bb->fall_through->fall_through = NULL;
+ bb->fall_through->taken = NULL;
+ }
+ break;
+
+ case Instruction::MOVE_RESULT_WIDE:
+ case Instruction::MOVE_RESULT:
+ case Instruction::MOVE_RESULT_OBJECT:
+ /*
+ * All move_results should have been folded into the preceeding invoke.
+ */
+ LOG(FATAL) << "Unexpected move_result";
+ break;
+
+ case Instruction::MONITOR_ENTER:
+ ConvertMonitorEnterExit(opt_flags,
+ art::llvm::IntrinsicHelper::MonitorEnter,
+ rl_src[0]);
+ break;
+
+ case Instruction::MONITOR_EXIT:
+ ConvertMonitorEnterExit(opt_flags,
+ art::llvm::IntrinsicHelper::MonitorExit,
+ rl_src[0]);
+ break;
+
+ case Instruction::ARRAY_LENGTH:
+ ConvertArrayLength(opt_flags, rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::NEW_ARRAY:
+ ConvertNewArray(vC, rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::INSTANCE_OF:
+ ConvertInstanceOf(vC, rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::AGET:
+ if (rl_dest.fp) {
+ ConvertAget(opt_flags,
+ art::llvm::IntrinsicHelper::HLArrayGetFloat,
+ rl_dest, rl_src[0], rl_src[1]);
+ } else {
+ ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGet,
+ rl_dest, rl_src[0], rl_src[1]);
+ }
+ break;
+ case Instruction::AGET_OBJECT:
+ ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetObject,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::AGET_BOOLEAN:
+ ConvertAget(opt_flags,
+ art::llvm::IntrinsicHelper::HLArrayGetBoolean,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::AGET_BYTE:
+ ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetByte,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::AGET_CHAR:
+ ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetChar,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::AGET_SHORT:
+ ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetShort,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::AGET_WIDE:
+ if (rl_dest.fp) {
+ ConvertAget(opt_flags,
+ art::llvm::IntrinsicHelper::HLArrayGetDouble,
+ rl_dest, rl_src[0], rl_src[1]);
+ } else {
+ ConvertAget(opt_flags, art::llvm::IntrinsicHelper::HLArrayGetWide,
+ rl_dest, rl_src[0], rl_src[1]);
+ }
+ break;
+
+ case Instruction::APUT:
+ if (rl_src[0].fp) {
+ ConvertAput(opt_flags,
+ art::llvm::IntrinsicHelper::HLArrayPutFloat,
+ rl_src[0], rl_src[1], rl_src[2]);
+ } else {
+ ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPut,
+ rl_src[0], rl_src[1], rl_src[2]);
+ }
+ break;
+ case Instruction::APUT_OBJECT:
+ ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutObject,
+ rl_src[0], rl_src[1], rl_src[2]);
+ break;
+ case Instruction::APUT_BOOLEAN:
+ ConvertAput(opt_flags,
+ art::llvm::IntrinsicHelper::HLArrayPutBoolean,
+ rl_src[0], rl_src[1], rl_src[2]);
+ break;
+ case Instruction::APUT_BYTE:
+ ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutByte,
+ rl_src[0], rl_src[1], rl_src[2]);
+ break;
+ case Instruction::APUT_CHAR:
+ ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutChar,
+ rl_src[0], rl_src[1], rl_src[2]);
+ break;
+ case Instruction::APUT_SHORT:
+ ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutShort,
+ rl_src[0], rl_src[1], rl_src[2]);
+ break;
+ case Instruction::APUT_WIDE:
+ if (rl_src[0].fp) {
+ ConvertAput(opt_flags,
+ art::llvm::IntrinsicHelper::HLArrayPutDouble,
+ rl_src[0], rl_src[1], rl_src[2]);
+ } else {
+ ConvertAput(opt_flags, art::llvm::IntrinsicHelper::HLArrayPutWide,
+ rl_src[0], rl_src[1], rl_src[2]);
+ }
+ break;
+
+ case Instruction::IGET:
+ if (rl_dest.fp) {
+ ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetFloat,
+ rl_dest, rl_src[0], vC);
+ } else {
+ ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGet,
+ rl_dest, rl_src[0], vC);
+ }
+ break;
+ case Instruction::IGET_OBJECT:
+ ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetObject,
+ rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::IGET_BOOLEAN:
+ ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetBoolean,
+ rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::IGET_BYTE:
+ ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetByte,
+ rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::IGET_CHAR:
+ ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetChar,
+ rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::IGET_SHORT:
+ ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetShort,
+ rl_dest, rl_src[0], vC);
+ break;
+ case Instruction::IGET_WIDE:
+ if (rl_dest.fp) {
+ ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetDouble,
+ rl_dest, rl_src[0], vC);
+ } else {
+ ConvertIget(opt_flags, art::llvm::IntrinsicHelper::HLIGetWide,
+ rl_dest, rl_src[0], vC);
+ }
+ break;
+ case Instruction::IPUT:
+ if (rl_src[0].fp) {
+ ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutFloat,
+ rl_src[0], rl_src[1], vC);
+ } else {
+ ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPut,
+ rl_src[0], rl_src[1], vC);
+ }
+ break;
+ case Instruction::IPUT_OBJECT:
+ ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutObject,
+ rl_src[0], rl_src[1], vC);
+ break;
+ case Instruction::IPUT_BOOLEAN:
+ ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutBoolean,
+ rl_src[0], rl_src[1], vC);
+ break;
+ case Instruction::IPUT_BYTE:
+ ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutByte,
+ rl_src[0], rl_src[1], vC);
+ break;
+ case Instruction::IPUT_CHAR:
+ ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutChar,
+ rl_src[0], rl_src[1], vC);
+ break;
+ case Instruction::IPUT_SHORT:
+ ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutShort,
+ rl_src[0], rl_src[1], vC);
+ break;
+ case Instruction::IPUT_WIDE:
+ if (rl_src[0].fp) {
+ ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutDouble,
+ rl_src[0], rl_src[1], vC);
+ } else {
+ ConvertIput(opt_flags, art::llvm::IntrinsicHelper::HLIPutWide,
+ rl_src[0], rl_src[1], vC);
+ }
+ break;
+
+ case Instruction::FILL_ARRAY_DATA:
+ ConvertFillArrayData(vB, rl_src[0]);
+ break;
+
+ case Instruction::LONG_TO_INT:
+ ConvertLongToInt(rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::INT_TO_LONG:
+ ConvertIntToLong(rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::INT_TO_CHAR:
+ ConvertIntNarrowing(rl_dest, rl_src[0],
+ art::llvm::IntrinsicHelper::IntToChar);
+ break;
+ case Instruction::INT_TO_BYTE:
+ ConvertIntNarrowing(rl_dest, rl_src[0],
+ art::llvm::IntrinsicHelper::IntToByte);
+ break;
+ case Instruction::INT_TO_SHORT:
+ ConvertIntNarrowing(rl_dest, rl_src[0],
+ art::llvm::IntrinsicHelper::IntToShort);
+ break;
+
+ case Instruction::INT_TO_FLOAT:
+ case Instruction::LONG_TO_FLOAT:
+ ConvertIntToFP(irb_->getFloatTy(), rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::INT_TO_DOUBLE:
+ case Instruction::LONG_TO_DOUBLE:
+ ConvertIntToFP(irb_->getDoubleTy(), rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::FLOAT_TO_DOUBLE:
+ ConvertFloatToDouble(rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::DOUBLE_TO_FLOAT:
+ ConvertDoubleToFloat(rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::NEG_LONG:
+ case Instruction::NEG_INT:
+ ConvertNeg(rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::NEG_FLOAT:
+ case Instruction::NEG_DOUBLE:
+ ConvertNegFP(rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::NOT_LONG:
+ case Instruction::NOT_INT:
+ ConvertNot(rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::FLOAT_TO_INT:
+ ConvertFPToInt(art::llvm::IntrinsicHelper::F2I, rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::DOUBLE_TO_INT:
+ ConvertFPToInt(art::llvm::IntrinsicHelper::D2I, rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::FLOAT_TO_LONG:
+ ConvertFPToInt(art::llvm::IntrinsicHelper::F2L, rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::DOUBLE_TO_LONG:
+ ConvertFPToInt(art::llvm::IntrinsicHelper::D2L, rl_dest, rl_src[0]);
+ break;
+
+ case Instruction::CMPL_FLOAT:
+ ConvertWideComparison(art::llvm::IntrinsicHelper::CmplFloat,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::CMPG_FLOAT:
+ ConvertWideComparison(art::llvm::IntrinsicHelper::CmpgFloat,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::CMPL_DOUBLE:
+ ConvertWideComparison(art::llvm::IntrinsicHelper::CmplDouble,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::CMPG_DOUBLE:
+ ConvertWideComparison(art::llvm::IntrinsicHelper::CmpgDouble,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+ case Instruction::CMP_LONG:
+ ConvertWideComparison(art::llvm::IntrinsicHelper::CmpLong,
+ rl_dest, rl_src[0], rl_src[1]);
+ break;
+
+ case Instruction::PACKED_SWITCH:
+ ConvertPackedSwitch(bb, vB, rl_src[0]);
+ break;
+
+ case Instruction::SPARSE_SWITCH:
+ ConvertSparseSwitch(bb, vB, rl_src[0]);
+ break;
+
+ default:
+ UNIMPLEMENTED(FATAL) << "Unsupported Dex opcode 0x" << std::hex << opcode;
+ res = true;
+ }
+ return res;
+}
+
+void MirConverter::SetDexOffset(int32_t offset)
+{
+ current_dalvik_offset_ = offset;
+ ::llvm::SmallVector< ::llvm::Value*, 1> array_ref;
+ array_ref.push_back(irb_->getInt32(offset));
+ ::llvm::MDNode* node = ::llvm::MDNode::get(*context_, array_ref);
+ irb_->SetDexOffset(node);
+}
+
+// Attach method info as metadata to special intrinsic
+void MirConverter::SetMethodInfo()
+{
+ // We don't want dex offset on this
+ irb_->SetDexOffset(NULL);
+ art::llvm::IntrinsicHelper::IntrinsicId id;
+ id = art::llvm::IntrinsicHelper::MethodInfo;
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Instruction* inst = irb_->CreateCall(intr);
+ ::llvm::SmallVector< ::llvm::Value*, 2> reg_info;
+ reg_info.push_back(irb_->getInt32(cu_->num_ins));
+ reg_info.push_back(irb_->getInt32(cu_->num_regs));
+ reg_info.push_back(irb_->getInt32(cu_->num_outs));
+ reg_info.push_back(irb_->getInt32(cu_->num_compiler_temps));
+ reg_info.push_back(irb_->getInt32(mir_graph_->GetNumSSARegs()));
+ ::llvm::MDNode* reg_info_node = ::llvm::MDNode::get(*context_, reg_info);
+ inst->setMetadata("RegInfo", reg_info_node);
+ SetDexOffset(current_dalvik_offset_);
+}
+
+void MirConverter::HandlePhiNodes(BasicBlock* bb, ::llvm::BasicBlock* llvm_bb)
+{
+ SetDexOffset(bb->start_offset);
+ for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
+ int opcode = mir->dalvikInsn.opcode;
+ if (opcode < kMirOpFirst) {
+ // Stop after first non-pseudo MIR op.
+ continue;
+ }
+ if (opcode != kMirOpPhi) {
+ // Skip other mir Pseudos.
+ continue;
+ }
+ RegLocation rl_dest = mir_graph_->reg_location_[mir->ssa_rep->defs[0]];
+ /*
+ * The Art compiler's Phi nodes only handle 32-bit operands,
+ * representing wide values using a matched set of Phi nodes
+ * for the lower and upper halves. In the llvm world, we only
+ * want a single Phi for wides. Here we will simply discard
+ * the Phi node representing the high word.
+ */
+ if (rl_dest.high_word) {
+ continue; // No Phi node - handled via low word
+ }
+ int* incoming = reinterpret_cast<int*>(mir->dalvikInsn.vB);
+ ::llvm::Type* phi_type =
+ LlvmTypeFromLocRec(rl_dest);
+ ::llvm::PHINode* phi = irb_->CreatePHI(phi_type, mir->ssa_rep->num_uses);
+ for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
+ RegLocation loc;
+ // Don't check width here.
+ loc = mir_graph_->GetRawSrc(mir, i);
+ DCHECK_EQ(rl_dest.wide, loc.wide);
+ DCHECK_EQ(rl_dest.wide & rl_dest.high_word, loc.wide & loc.high_word);
+ DCHECK_EQ(rl_dest.fp, loc.fp);
+ DCHECK_EQ(rl_dest.core, loc.core);
+ DCHECK_EQ(rl_dest.ref, loc.ref);
+ SafeMap<unsigned int, unsigned int>::iterator it;
+ it = mir_graph_->block_id_map_.find(incoming[i]);
+ DCHECK(it != mir_graph_->block_id_map_.end());
+ DCHECK(GetLLVMValue(loc.orig_sreg) != NULL);
+ DCHECK(GetLLVMBlock(it->second) != NULL);
+ phi->addIncoming(GetLLVMValue(loc.orig_sreg),
+ GetLLVMBlock(it->second));
+ }
+ DefineValueOnly(phi, rl_dest.orig_sreg);
+ }
+}
+
+/* Extended MIR instructions like PHI */
+void MirConverter::ConvertExtendedMIR(BasicBlock* bb, MIR* mir,
+ ::llvm::BasicBlock* llvm_bb)
+{
+
+ switch (static_cast<ExtendedMIROpcode>(mir->dalvikInsn.opcode)) {
+ case kMirOpPhi: {
+ // The llvm Phi node already emitted - just DefineValue() here.
+ RegLocation rl_dest = mir_graph_->reg_location_[mir->ssa_rep->defs[0]];
+ if (!rl_dest.high_word) {
+ // Only consider low word of pairs.
+ DCHECK(GetLLVMValue(rl_dest.orig_sreg) != NULL);
+ ::llvm::Value* phi = GetLLVMValue(rl_dest.orig_sreg);
+ if (1) SetVregOnValue(phi, rl_dest.orig_sreg);
+ }
+ break;
+ }
+ case kMirOpCopy: {
+ UNIMPLEMENTED(WARNING) << "unimp kMirOpPhi";
+ break;
+ }
+ case kMirOpNop:
+ if ((mir == bb->last_mir_insn) && (bb->taken == NULL) &&
+ (bb->fall_through == NULL)) {
+ irb_->CreateUnreachable();
+ }
+ break;
+
+ // TODO: need GBC intrinsic to take advantage of fused operations
+ case kMirOpFusedCmplFloat:
+ UNIMPLEMENTED(FATAL) << "kMirOpFusedCmpFloat unsupported";
+ break;
+ case kMirOpFusedCmpgFloat:
+ UNIMPLEMENTED(FATAL) << "kMirOpFusedCmgFloat unsupported";
+ break;
+ case kMirOpFusedCmplDouble:
+ UNIMPLEMENTED(FATAL) << "kMirOpFusedCmplDouble unsupported";
+ break;
+ case kMirOpFusedCmpgDouble:
+ UNIMPLEMENTED(FATAL) << "kMirOpFusedCmpgDouble unsupported";
+ break;
+ case kMirOpFusedCmpLong:
+ UNIMPLEMENTED(FATAL) << "kMirOpLongCmpBranch unsupported";
+ break;
+ default:
+ break;
+ }
+}
+
+/* Handle the content in each basic block */
+bool MirConverter::BlockBitcodeConversion(BasicBlock* bb)
+{
+ if (bb->block_type == kDead) return false;
+ ::llvm::BasicBlock* llvm_bb = GetLLVMBlock(bb->id);
+ if (llvm_bb == NULL) {
+ CHECK(bb->block_type == kExitBlock);
+ } else {
+ irb_->SetInsertPoint(llvm_bb);
+ SetDexOffset(bb->start_offset);
+ }
+
+ if (cu_->verbose) {
+ LOG(INFO) << "................................";
+ LOG(INFO) << "Block id " << bb->id;
+ if (llvm_bb != NULL) {
+ LOG(INFO) << "label " << llvm_bb->getName().str().c_str();
+ } else {
+ LOG(INFO) << "llvm_bb is NULL";
+ }
+ }
+
+ if (bb->block_type == kEntryBlock) {
+ SetMethodInfo();
+
+ { // Allocate shadowframe.
+ art::llvm::IntrinsicHelper::IntrinsicId id =
+ art::llvm::IntrinsicHelper::AllocaShadowFrame;
+ ::llvm::Function* func = intrinsic_helper_->GetIntrinsicFunction(id);
+ ::llvm::Value* entries = irb_->getInt32(cu_->num_dalvik_registers);
+ irb_->CreateCall(func, entries);
+ }
+
+ { // Store arguments to vregs.
+ uint16_t arg_reg = cu_->num_regs;
+
+ ::llvm::Function::arg_iterator arg_iter(func_->arg_begin());
+ ::llvm::Function::arg_iterator arg_end(func_->arg_end());
+
+ const char* shorty = cu_->shorty;
+ uint32_t shorty_size = strlen(shorty);
+ CHECK_GE(shorty_size, 1u);
+
+ ++arg_iter; // skip method object
+
+ if ((cu_->access_flags & kAccStatic) == 0) {
+ SetVregOnValue(arg_iter, arg_reg);
+ ++arg_iter;
+ ++arg_reg;
+ }
+
+ for (uint32_t i = 1; i < shorty_size; ++i, ++arg_iter) {
+ SetVregOnValue(arg_iter, arg_reg);
+
+ ++arg_reg;
+ if (shorty[i] == 'J' || shorty[i] == 'D') {
+ // Wide types, such as long and double, are using a pair of registers
+ // to store the value, so we have to increase arg_reg again.
+ ++arg_reg;
+ }
+ }
+ }
+ } else if (bb->block_type == 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;
+ } else if (bb->block_type == kExceptionHandling) {
+ /*
+ * Because we're deferring null checking, delete the associated empty
+ * exception block.
+ */
+ llvm_bb->eraseFromParent();
+ return false;
+ }
+
+ HandlePhiNodes(bb, llvm_bb);
+
+ for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
+
+ SetDexOffset(mir->offset);
+
+ int opcode = mir->dalvikInsn.opcode;
+ Instruction::Format dalvik_format =
+ Instruction::FormatOf(mir->dalvikInsn.opcode);
+
+ if (opcode == kMirOpCheck) {
+ // Combine check and work halves of throwing instruction.
+ MIR* work_half = mir->meta.throw_insn;
+ mir->dalvikInsn.opcode = work_half->dalvikInsn.opcode;
+ opcode = mir->dalvikInsn.opcode;
+ SSARepresentation* ssa_rep = work_half->ssa_rep;
+ work_half->ssa_rep = mir->ssa_rep;
+ mir->ssa_rep = ssa_rep;
+ work_half->meta.original_opcode = work_half->dalvikInsn.opcode;
+ work_half->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+ if (bb->successor_block_list.block_list_type == kCatch) {
+ ::llvm::Function* intr = intrinsic_helper_->GetIntrinsicFunction(
+ art::llvm::IntrinsicHelper::CatchTargets);
+ ::llvm::Value* switch_key =
+ irb_->CreateCall(intr, irb_->getInt32(mir->offset));
+ GrowableArray<SuccessorBlockInfo*>::Iterator iter(bb->successor_block_list.blocks);
+ // New basic block to use for work half
+ ::llvm::BasicBlock* work_bb =
+ ::llvm::BasicBlock::Create(*context_, "", func_);
+ ::llvm::SwitchInst* sw =
+ irb_->CreateSwitch(switch_key, work_bb,
+ bb->successor_block_list.blocks->Size());
+ while (true) {
+ SuccessorBlockInfo *successor_block_info = iter.Next();
+ if (successor_block_info == NULL) break;
+ ::llvm::BasicBlock *target =
+ GetLLVMBlock(successor_block_info->block->id);
+ int type_index = successor_block_info->key;
+ sw->addCase(irb_->getInt32(type_index), target);
+ }
+ llvm_bb = work_bb;
+ irb_->SetInsertPoint(llvm_bb);
+ }
+ }
+
+ if (opcode >= kMirOpFirst) {
+ ConvertExtendedMIR(bb, mir, llvm_bb);
+ continue;
+ }
+
+ bool not_handled = ConvertMIRNode(mir, bb, llvm_bb);
+ if (not_handled) {
+ Instruction::Code dalvik_opcode = static_cast<Instruction::Code>(opcode);
+ LOG(WARNING) << StringPrintf("%#06x: Op %#x (%s) / Fmt %d not handled",
+ mir->offset, opcode,
+ Instruction::Name(dalvik_opcode),
+ dalvik_format);
+ }
+ }
+
+ if (bb->block_type == kEntryBlock) {
+ entry_target_bb_ = GetLLVMBlock(bb->fall_through->id);
+ } else if ((bb->fall_through != NULL) && !bb->terminated_by_return) {
+ irb_->CreateBr(GetLLVMBlock(bb->fall_through->id));
+ }
+
+ return false;
+}
+
+char RemapShorty(char shorty_type) {
+ /*
+ * TODO: might want to revisit this. Dalvik registers are 32-bits wide,
+ * and longs/doubles are represented as a pair of registers. When sub-word
+ * arguments (and method results) are passed, they are extended to Dalvik
+ * virtual register containers. Because llvm is picky about type consistency,
+ * we must either cast the "real" type to 32-bit container multiple Dalvik
+ * register types, or always use the expanded values.
+ * Here, we're doing the latter. We map the shorty signature to container
+ * types (which is valid so long as we always do a real expansion of passed
+ * arguments and field loads).
+ */
+ switch(shorty_type) {
+ case 'Z' : shorty_type = 'I'; break;
+ case 'B' : shorty_type = 'I'; break;
+ case 'S' : shorty_type = 'I'; break;
+ case 'C' : shorty_type = 'I'; break;
+ default: break;
+ }
+ return shorty_type;
+}
+
+::llvm::FunctionType* MirConverter::GetFunctionType() {
+
+ // Get return type
+ ::llvm::Type* ret_type = irb_->getJType(RemapShorty(cu_->shorty[0]));
+
+ // Get argument type
+ std::vector< ::llvm::Type*> args_type;
+
+ // method object
+ args_type.push_back(irb_->getJMethodTy());
+
+ // Do we have a "this"?
+ if ((cu_->access_flags & kAccStatic) == 0) {
+ args_type.push_back(irb_->getJObjectTy());
+ }
+
+ for (uint32_t i = 1; i < strlen(cu_->shorty); ++i) {
+ args_type.push_back(irb_->getJType(RemapShorty(cu_->shorty[i])));
+ }
+
+ return ::llvm::FunctionType::get(ret_type, args_type, false);
+}
+
+bool MirConverter::CreateFunction() {
+ ::llvm::FunctionType* func_type = GetFunctionType();
+ if (func_type == NULL) {
+ return false;
+ }
+
+ func_ = ::llvm::Function::Create(func_type,
+ ::llvm::Function::InternalLinkage,
+ symbol_, module_);
+
+ ::llvm::Function::arg_iterator arg_iter(func_->arg_begin());
+ ::llvm::Function::arg_iterator arg_end(func_->arg_end());
+
+ arg_iter->setName("method");
+ ++arg_iter;
+
+ int start_sreg = cu_->num_regs;
+
+ for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) {
+ arg_iter->setName(StringPrintf("v%i_0", start_sreg));
+ start_sreg += mir_graph_->reg_location_[start_sreg].wide ? 2 : 1;
+ }
+
+ return true;
+}
+
+bool MirConverter::CreateLLVMBasicBlock(BasicBlock* bb)
+{
+ // Skip the exit block
+ if ((bb->block_type == kDead) ||(bb->block_type == kExitBlock)) {
+ id_to_block_map_.Put(bb->id, NULL);
+ } else {
+ int offset = bb->start_offset;
+ bool entry_block = (bb->block_type == kEntryBlock);
+ ::llvm::BasicBlock* llvm_bb =
+ ::llvm::BasicBlock::Create(*context_, entry_block ? "entry" :
+ StringPrintf(kLabelFormat, bb->catch_entry ? kCatchBlock :
+ kNormalBlock, offset, bb->id), func_);
+ if (entry_block) {
+ entry_bb_ = llvm_bb;
+ placeholder_bb_ =
+ ::llvm::BasicBlock::Create(*context_, "placeholder",
+ func_);
+ }
+ id_to_block_map_.Put(bb->id, llvm_bb);
+ }
+ 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 MirConverter::MethodMIR2Bitcode()
+{
+ InitIR();
+
+ // Create the function
+ CreateFunction();
+
+ // Create an LLVM basic block for each MIR block in dfs preorder
+ PreOrderDfsIterator iter(mir_graph_, false /* not iterative */);
+ for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
+ CreateLLVMBasicBlock(bb);
+ }
+
+ /*
+ * 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).
+ */
+ irb_->SetInsertPoint(placeholder_bb_);
+ ::llvm::Function::arg_iterator arg_iter(func_->arg_begin());
+ arg_iter++; /* Skip path method */
+ for (int i = 0; i < mir_graph_->GetNumSSARegs(); i++) {
+ ::llvm::Value* val;
+ RegLocation rl_temp = mir_graph_->reg_location_[i];
+ if ((mir_graph_->SRegToVReg(i) < 0) || rl_temp.high_word) {
+ llvm_values_.Insert(0);
+ } else if ((i < cu_->num_regs) ||
+ (i >= (cu_->num_regs + cu_->num_ins))) {
+ ::llvm::Constant* imm_value = mir_graph_->reg_location_[i].wide ?
+ irb_->getJLong(0) : irb_->getJInt(0);
+ val = EmitConst(imm_value, mir_graph_->reg_location_[i]);
+ val->setName(mir_graph_->GetSSAName(i));
+ llvm_values_.Insert(val);
+ } else {
+ // Recover previously-created argument values
+ ::llvm::Value* arg_val = arg_iter++;
+ llvm_values_.Insert(arg_val);
+ }
+ }
+
+ PreOrderDfsIterator iter2(mir_graph_, false /* not iterative */);
+ for (BasicBlock* bb = iter2.Next(); bb != NULL; bb = iter2.Next()) {
+ BlockBitcodeConversion(bb);
+ }
+
+ /*
+ * In a few rare cases of verification failure, the verifier will
+ * replace one or more Dalvik opcodes with the special
+ * throw-verification-failure opcode. This can leave the SSA graph
+ * in an invalid state, as definitions may be lost, while uses retained.
+ * To work around this problem, we insert placeholder definitions for
+ * all Dalvik SSA regs in the "placeholder" block. Here, after
+ * bitcode conversion is complete, we examine those placeholder definitions
+ * and delete any with no references (which normally is all of them).
+ *
+ * If any definitions remain, we link the placeholder block into the
+ * CFG. Otherwise, it is deleted.
+ */
+ for (::llvm::BasicBlock::iterator it = placeholder_bb_->begin(),
+ it_end = placeholder_bb_->end(); it != it_end;) {
+ ::llvm::Instruction* inst = ::llvm::dyn_cast< ::llvm::Instruction>(it++);
+ DCHECK(inst != NULL);
+ ::llvm::Value* val = ::llvm::dyn_cast< ::llvm::Value>(inst);
+ DCHECK(val != NULL);
+ if (val->getNumUses() == 0) {
+ inst->eraseFromParent();
+ }
+ }
+ SetDexOffset(0);
+ if (placeholder_bb_->empty()) {
+ placeholder_bb_->eraseFromParent();
+ } else {
+ irb_->SetInsertPoint(placeholder_bb_);
+ irb_->CreateBr(entry_target_bb_);
+ entry_target_bb_ = placeholder_bb_;
+ }
+ irb_->SetInsertPoint(entry_bb_);
+ irb_->CreateBr(entry_target_bb_);
+
+ if (cu_->enable_debug & (1 << kDebugVerifyBitcode)) {
+ if (::llvm::verifyFunction(*func_, ::llvm::PrintMessageAction)) {
+ LOG(INFO) << "Bitcode verification FAILED for "
+ << PrettyMethod(cu_->method_idx, *cu_->dex_file)
+ << " of size " << cu_->code_item->insns_size_in_code_units_;
+ cu_->enable_debug |= (1 << kDebugDumpBitcodeFile);
+ }
+ }
+
+ if (cu_->enable_debug & (1 << kDebugDumpBitcodeFile)) {
+ // Write bitcode to file
+ std::string errmsg;
+ std::string fname(PrettyMethod(cu_->method_idx, *cu_->dex_file));
+ mir_graph_->ReplaceSpecialChars(fname);
+ // TODO: make configurable change naming mechanism to avoid fname length issues.
+ fname = StringPrintf("/sdcard/Bitcode/%s.bc", fname.c_str());
+
+ if (fname.size() > 240) {
+ LOG(INFO) << "Warning: bitcode filename too long. Truncated.";
+ fname.resize(240);
+ }
+
+ ::llvm::OwningPtr< ::llvm::tool_output_file> out_file(
+ new ::llvm::tool_output_file(fname.c_str(), errmsg,
+ ::llvm::raw_fd_ostream::F_Binary));
+
+ if (!errmsg.empty()) {
+ LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
+ }
+
+ ::llvm::WriteBitcodeToFile(module_, out_file->os());
+ out_file->keep();
+ }
+}
+
+Backend* PortableCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
+ ArenaAllocator* const arena,
+ llvm::LlvmCompilationUnit* const llvm_compilation_unit) {
+ return new MirConverter(cu, mir_graph, arena, llvm_compilation_unit);
+}
+
+} // namespace art