blob: e38977ad109fb953ffd221e2a2fafac31db38834 [file] [log] [blame]
/*
* 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/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>
#include <llvm/Support/InstIterator.h>
#include "../compiler_internals.h"
#include "local_optimizations.h"
#include "codegen_util.h"
#include "ralloc_util.h"
static const char* kLabelFormat = "%c0x%x_%d";
static const char kInvalidBlock = 0xff;
static const char kNormalBlock = 'L';
static const char kCatchBlock = 'C';
namespace art {
static RegLocation GetLoc(CompilationUnit* cu, llvm::Value* val);
static llvm::BasicBlock* GetLLVMBlock(CompilationUnit* cu, int id)
{
return cu->id_to_block_map.Get(id);
}
static llvm::Value* GetLLVMValue(CompilationUnit* cu, int s_reg)
{
return reinterpret_cast<llvm::Value*>(GrowableListGetElement(&cu->llvm_values, s_reg));
}
static void SetVregOnValue(CompilationUnit* cu, llvm::Value* val, int s_reg)
{
// Set vreg for debugging
greenland::IntrinsicHelper::IntrinsicId id =
greenland::IntrinsicHelper::SetVReg;
llvm::Function* func = cu->intrinsic_helper->GetIntrinsicFunction(id);
int v_reg = SRegToVReg(cu, s_reg);
llvm::Value* table_slot = cu->irb->getInt32(v_reg);
llvm::Value* args[] = { table_slot, val };
cu->irb->CreateCall(func, args);
}
// Replace the placeholder value with the real definition
static void DefineValueOnly(CompilationUnit* cu, llvm::Value* val, int s_reg)
{
llvm::Value* placeholder = GetLLVMValue(cu, 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);
cu->llvm_values.elem_list[s_reg] = reinterpret_cast<uintptr_t>(val);
llvm::Instruction* inst = llvm::dyn_cast<llvm::Instruction>(placeholder);
DCHECK(inst != NULL);
inst->eraseFromParent();
}
static void DefineValue(CompilationUnit* cu, llvm::Value* val, int s_reg)
{
DefineValueOnly(cu, val, s_reg);
SetVregOnValue(cu, val, s_reg);
}
static llvm::Type* LlvmTypeFromLocRec(CompilationUnit* cu, RegLocation loc)
{
llvm::Type* res = NULL;
if (loc.wide) {
if (loc.fp)
res = cu->irb->getDoubleTy();
else
res = cu->irb->getInt64Ty();
} else {
if (loc.fp) {
res = cu->irb->getFloatTy();
} else {
if (loc.ref)
res = cu->irb->GetJObjectTy();
else
res = cu->irb->getInt32Ty();
}
}
return res;
}
/* Create an in-memory RegLocation from an llvm Value. */
static void CreateLocFromValue(CompilationUnit* cu, llvm::Value* val)
{
// NOTE: llvm takes shortcuts with c_str() - get to std::string firstt
std::string s(val->getName().str());
const char* val_name = s.c_str();
SafeMap<llvm::Value*, RegLocation>::iterator it = cu->loc_map.find(val);
DCHECK(it == cu->loc_map.end()) << " - already defined: " << val_name;
int base_sreg = INVALID_SREG;
int subscript = -1;
sscanf(val_name, "v%d_%d", &base_sreg, &subscript);
if ((base_sreg == INVALID_SREG) && (!strcmp(val_name, "method"))) {
base_sreg = SSA_METHOD_BASEREG;
subscript = 0;
}
DCHECK_NE(base_sreg, INVALID_SREG);
DCHECK_NE(subscript, -1);
// TODO: redo during C++'ification
RegLocation loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, INVALID_REG,
INVALID_REG, INVALID_SREG, INVALID_SREG};
llvm::Type* ty = val->getType();
loc.wide = ((ty == cu->irb->getInt64Ty()) ||
(ty == cu->irb->getDoubleTy()));
loc.defined = true;
loc.home = false; // May change during promotion
loc.s_reg_low = base_sreg;
loc.orig_sreg = cu->loc_map.size();
PromotionMap p_map = cu->promotion_map[base_sreg];
if (ty == cu->irb->getFloatTy()) {
loc.fp = true;
if (p_map.fp_location == kLocPhysReg) {
loc.low_reg = p_map.FpReg;
loc.location = kLocPhysReg;
loc.home = true;
}
} else if (ty == cu->irb->getDoubleTy()) {
loc.fp = true;
PromotionMap p_map_high = cu->promotion_map[base_sreg + 1];
if ((p_map.fp_location == kLocPhysReg) &&
(p_map_high.fp_location == kLocPhysReg) &&
((p_map.FpReg & 0x1) == 0) &&
(p_map.FpReg + 1 == p_map_high.FpReg)) {
loc.low_reg = p_map.FpReg;
loc.high_reg = p_map_high.FpReg;
loc.location = kLocPhysReg;
loc.home = true;
}
} else if (ty == cu->irb->GetJObjectTy()) {
loc.ref = true;
if (p_map.core_location == kLocPhysReg) {
loc.low_reg = p_map.core_reg;
loc.location = kLocPhysReg;
loc.home = true;
}
} else if (ty == cu->irb->getInt64Ty()) {
loc.core = true;
PromotionMap p_map_high = cu->promotion_map[base_sreg + 1];
if ((p_map.core_location == kLocPhysReg) &&
(p_map_high.core_location == kLocPhysReg)) {
loc.low_reg = p_map.core_reg;
loc.high_reg = p_map_high.core_reg;
loc.location = kLocPhysReg;
loc.home = true;
}
} else {
loc.core = true;
if (p_map.core_location == kLocPhysReg) {
loc.low_reg = p_map.core_reg;
loc.location = kLocPhysReg;
loc.home = true;
}
}
if (cu->verbose && loc.home) {
if (loc.wide) {
LOG(INFO) << "Promoted wide " << s << " to regs " << loc.low_reg << "/" << loc.high_reg;
} else {
LOG(INFO) << "Promoted " << s << " to reg " << loc.low_reg;
}
}
cu->loc_map.Put(val, loc);
}
static void InitIR(CompilationUnit* cu)
{
LLVMInfo* llvm_info = cu->llvm_info;
if (llvm_info == NULL) {
CompilerTls* tls = cu->compiler->GetTls();
CHECK(tls != NULL);
llvm_info = static_cast<LLVMInfo*>(tls->GetLLVMInfo());
if (llvm_info == NULL) {
llvm_info = new LLVMInfo();
tls->SetLLVMInfo(llvm_info);
}
}
cu->context = llvm_info->GetLLVMContext();
cu->module = llvm_info->GetLLVMModule();
cu->intrinsic_helper = llvm_info->GetIntrinsicHelper();
cu->irb = llvm_info->GetIRBuilder();
}
static const char* LlvmSSAName(CompilationUnit* cu, int ssa_reg) {
return GET_ELEM_N(cu->ssa_strings, char*, ssa_reg);
}
llvm::BasicBlock* FindCaseTarget(CompilationUnit* cu, uint32_t vaddr)
{
BasicBlock* bb = FindBlock(cu, vaddr);
DCHECK(bb != NULL);
return GetLLVMBlock(cu, bb->id);
}
static void ConvertPackedSwitch(CompilationUnit* cu, BasicBlock* bb,
int32_t table_offset, RegLocation rl_src)
{
const Instruction::PackedSwitchPayload* payload =
reinterpret_cast<const Instruction::PackedSwitchPayload*>(
cu->insns + cu->current_dalvik_offset + table_offset);
llvm::Value* value = GetLLVMValue(cu, rl_src.orig_sreg);
llvm::SwitchInst* sw =
cu->irb->CreateSwitch(value, GetLLVMBlock(cu, bb->fall_through->id),
payload->case_count);
for (uint16_t i = 0; i < payload->case_count; ++i) {
llvm::BasicBlock* llvm_bb =
FindCaseTarget(cu, cu->current_dalvik_offset + payload->targets[i]);
sw->addCase(cu->irb->getInt32(payload->first_key + i), llvm_bb);
}
llvm::MDNode* switch_node =
llvm::MDNode::get(*cu->context, cu->irb->getInt32(table_offset));
sw->setMetadata("SwitchTable", switch_node);
bb->taken = NULL;
bb->fall_through = NULL;
}
static void ConvertSparseSwitch(CompilationUnit* cu, BasicBlock* bb,
int32_t table_offset, RegLocation rl_src)
{
const Instruction::SparseSwitchPayload* payload =
reinterpret_cast<const Instruction::SparseSwitchPayload*>(
cu->insns + cu->current_dalvik_offset + table_offset);
const int32_t* keys = payload->GetKeys();
const int32_t* targets = payload->GetTargets();
llvm::Value* value = GetLLVMValue(cu, rl_src.orig_sreg);
llvm::SwitchInst* sw =
cu->irb->CreateSwitch(value, GetLLVMBlock(cu, bb->fall_through->id),
payload->case_count);
for (size_t i = 0; i < payload->case_count; ++i) {
llvm::BasicBlock* llvm_bb =
FindCaseTarget(cu, cu->current_dalvik_offset + targets[i]);
sw->addCase(cu->irb->getInt32(keys[i]), llvm_bb);
}
llvm::MDNode* switch_node =
llvm::MDNode::get(*cu->context, cu->irb->getInt32(table_offset));
sw->setMetadata("SwitchTable", switch_node);
bb->taken = NULL;
bb->fall_through = NULL;
}
static void ConvertSget(CompilationUnit* cu, int32_t field_index,
greenland::IntrinsicHelper::IntrinsicId id, RegLocation rl_dest)
{
llvm::Constant* field_idx = cu->irb->getInt32(field_index);
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Value* res = cu->irb->CreateCall(intr, field_idx);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertSput(CompilationUnit* cu, int32_t field_index,
greenland::IntrinsicHelper::IntrinsicId id, RegLocation rl_src)
{
llvm::SmallVector<llvm::Value*, 2> args;
args.push_back(cu->irb->getInt32(field_index));
args.push_back(GetLLVMValue(cu, rl_src.orig_sreg));
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
cu->irb->CreateCall(intr, args);
}
static void ConvertFillArrayData(CompilationUnit* cu, int32_t offset, RegLocation rl_array)
{
greenland::IntrinsicHelper::IntrinsicId id;
id = greenland::IntrinsicHelper::HLFillArrayData;
llvm::SmallVector<llvm::Value*, 2> args;
args.push_back(cu->irb->getInt32(offset));
args.push_back(GetLLVMValue(cu, rl_array.orig_sreg));
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
cu->irb->CreateCall(intr, args);
}
static llvm::Value* EmitConst(CompilationUnit* cu, 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;
} else if (loc.ref) {
id = greenland::IntrinsicHelper::ConstObj;
} else {
id = greenland::IntrinsicHelper::ConstInt;
}
}
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
return cu->irb->CreateCall(intr, src);
}
static void EmitPopShadowFrame(CompilationUnit* cu)
{
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(
greenland::IntrinsicHelper::PopShadowFrame);
cu->irb->CreateCall(intr);
}
static llvm::Value* EmitCopy(CompilationUnit* cu, 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;
} else if (loc.ref) {
id = greenland::IntrinsicHelper::CopyObj;
} else {
id = greenland::IntrinsicHelper::CopyInt;
}
}
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
return cu->irb->CreateCall(intr, src);
}
static void ConvertMoveException(CompilationUnit* cu, RegLocation rl_dest)
{
llvm::Function* func = cu->intrinsic_helper->GetIntrinsicFunction(
greenland::IntrinsicHelper::GetException);
llvm::Value* res = cu->irb->CreateCall(func);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertThrow(CompilationUnit* cu, RegLocation rl_src)
{
llvm::Value* src = GetLLVMValue(cu, rl_src.orig_sreg);
llvm::Function* func = cu->intrinsic_helper->GetIntrinsicFunction(
greenland::IntrinsicHelper::HLThrowException);
cu->irb->CreateCall(func, src);
}
static void ConvertMonitorEnterExit(CompilationUnit* cu, int opt_flags,
greenland::IntrinsicHelper::IntrinsicId id,
RegLocation rl_src)
{
llvm::SmallVector<llvm::Value*, 2> args;
args.push_back(cu->irb->getInt32(opt_flags));
args.push_back(GetLLVMValue(cu, rl_src.orig_sreg));
llvm::Function* func = cu->intrinsic_helper->GetIntrinsicFunction(id);
cu->irb->CreateCall(func, args);
}
static void ConvertArrayLength(CompilationUnit* cu, int opt_flags,
RegLocation rl_dest, RegLocation rl_src)
{
llvm::SmallVector<llvm::Value*, 2> args;
args.push_back(cu->irb->getInt32(opt_flags));
args.push_back(GetLLVMValue(cu, rl_src.orig_sreg));
llvm::Function* func = cu->intrinsic_helper->GetIntrinsicFunction(
greenland::IntrinsicHelper::OptArrayLength);
llvm::Value* res = cu->irb->CreateCall(func, args);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void EmitSuspendCheck(CompilationUnit* cu)
{
greenland::IntrinsicHelper::IntrinsicId id =
greenland::IntrinsicHelper::CheckSuspend;
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
cu->irb->CreateCall(intr);
}
static llvm::Value* ConvertCompare(CompilationUnit* cu, ConditionCode cc,
llvm::Value* src1, llvm::Value* src2)
{
llvm::Value* res = NULL;
DCHECK_EQ(src1->getType(), src2->getType());
switch(cc) {
case kCondEq: res = cu->irb->CreateICmpEQ(src1, src2); break;
case kCondNe: res = cu->irb->CreateICmpNE(src1, src2); break;
case kCondLt: res = cu->irb->CreateICmpSLT(src1, src2); break;
case kCondGe: res = cu->irb->CreateICmpSGE(src1, src2); break;
case kCondGt: res = cu->irb->CreateICmpSGT(src1, src2); break;
case kCondLe: res = cu->irb->CreateICmpSLE(src1, src2); break;
default: LOG(FATAL) << "Unexpected cc value " << cc;
}
return res;
}
static void ConvertCompareAndBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir,
ConditionCode cc, RegLocation rl_src1, RegLocation rl_src2)
{
if (bb->taken->start_offset <= mir->offset) {
EmitSuspendCheck(cu);
}
llvm::Value* src1 = GetLLVMValue(cu, rl_src1.orig_sreg);
llvm::Value* src2 = GetLLVMValue(cu, rl_src2.orig_sreg);
llvm::Value* cond_value = ConvertCompare(cu, cc, src1, src2);
cond_value->setName(StringPrintf("t%d", cu->temp_name++));
cu->irb->CreateCondBr(cond_value, GetLLVMBlock(cu, bb->taken->id),
GetLLVMBlock(cu, bb->fall_through->id));
// Don't redo the fallthrough branch in the BB driver
bb->fall_through = NULL;
}
static void ConvertCompareZeroAndBranch(CompilationUnit* cu, BasicBlock* bb,
MIR* mir, ConditionCode cc, RegLocation rl_src1)
{
if (bb->taken->start_offset <= mir->offset) {
EmitSuspendCheck(cu);
}
llvm::Value* src1 = GetLLVMValue(cu, rl_src1.orig_sreg);
llvm::Value* src2;
if (rl_src1.ref) {
src2 = cu->irb->GetJNull();
} else {
src2 = cu->irb->getInt32(0);
}
llvm::Value* cond_value = ConvertCompare(cu, cc, src1, src2);
cu->irb->CreateCondBr(cond_value, GetLLVMBlock(cu, bb->taken->id),
GetLLVMBlock(cu, bb->fall_through->id));
// Don't redo the fallthrough branch in the BB driver
bb->fall_through = NULL;
}
static llvm::Value* GenDivModOp(CompilationUnit* cu, bool is_div, bool is_long,
llvm::Value* src1, llvm::Value* src2)
{
greenland::IntrinsicHelper::IntrinsicId id;
if (is_long) {
if (is_div) {
id = greenland::IntrinsicHelper::DivLong;
} else {
id = greenland::IntrinsicHelper::RemLong;
}
} else {
if (is_div) {
id = greenland::IntrinsicHelper::DivInt;
} else {
id = greenland::IntrinsicHelper::RemInt;
}
}
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::SmallVector<llvm::Value*, 2>args;
args.push_back(src1);
args.push_back(src2);
return cu->irb->CreateCall(intr, args);
}
static llvm::Value* GenArithOp(CompilationUnit* cu, OpKind op, bool is_long,
llvm::Value* src1, llvm::Value* src2)
{
llvm::Value* res = NULL;
switch(op) {
case kOpAdd: res = cu->irb->CreateAdd(src1, src2); break;
case kOpSub: res = cu->irb->CreateSub(src1, src2); break;
case kOpRsub: res = cu->irb->CreateSub(src2, src1); break;
case kOpMul: res = cu->irb->CreateMul(src1, src2); break;
case kOpOr: res = cu->irb->CreateOr(src1, src2); break;
case kOpAnd: res = cu->irb->CreateAnd(src1, src2); break;
case kOpXor: res = cu->irb->CreateXor(src1, src2); break;
case kOpDiv: res = GenDivModOp(cu, true, is_long, src1, src2); break;
case kOpRem: res = GenDivModOp(cu, false, is_long, src1, src2); break;
case kOpLsl: res = cu->irb->CreateShl(src1, src2); break;
case kOpLsr: res = cu->irb->CreateLShr(src1, src2); break;
case kOpAsr: res = cu->irb->CreateAShr(src1, src2); break;
default:
LOG(FATAL) << "Invalid op " << op;
}
return res;
}
static void ConvertFPArithOp(CompilationUnit* cu, OpKind op, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2)
{
llvm::Value* src1 = GetLLVMValue(cu, rl_src1.orig_sreg);
llvm::Value* src2 = GetLLVMValue(cu, rl_src2.orig_sreg);
llvm::Value* res = NULL;
switch(op) {
case kOpAdd: res = cu->irb->CreateFAdd(src1, src2); break;
case kOpSub: res = cu->irb->CreateFSub(src1, src2); break;
case kOpMul: res = cu->irb->CreateFMul(src1, src2); break;
case kOpDiv: res = cu->irb->CreateFDiv(src1, src2); break;
case kOpRem: res = cu->irb->CreateFRem(src1, src2); break;
default:
LOG(FATAL) << "Invalid op " << op;
}
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertShift(CompilationUnit* cu, greenland::IntrinsicHelper::IntrinsicId id,
RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
{
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::SmallVector<llvm::Value*, 2>args;
args.push_back(GetLLVMValue(cu, rl_src1.orig_sreg));
args.push_back(GetLLVMValue(cu, rl_src2.orig_sreg));
llvm::Value* res = cu->irb->CreateCall(intr, args);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertShiftLit(CompilationUnit* cu, greenland::IntrinsicHelper::IntrinsicId id,
RegLocation rl_dest, RegLocation rl_src, int shift_amount)
{
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::SmallVector<llvm::Value*, 2>args;
args.push_back(GetLLVMValue(cu, rl_src.orig_sreg));
args.push_back(cu->irb->getInt32(shift_amount));
llvm::Value* res = cu->irb->CreateCall(intr, args);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertArithOp(CompilationUnit* cu, OpKind op, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2)
{
llvm::Value* src1 = GetLLVMValue(cu, rl_src1.orig_sreg);
llvm::Value* src2 = GetLLVMValue(cu, rl_src2.orig_sreg);
DCHECK_EQ(src1->getType(), src2->getType());
llvm::Value* res = GenArithOp(cu, op, rl_dest.wide, src1, src2);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertArithOpLit(CompilationUnit* cu, OpKind op, RegLocation rl_dest,
RegLocation rl_src1, int32_t imm)
{
llvm::Value* src1 = GetLLVMValue(cu, rl_src1.orig_sreg);
llvm::Value* src2 = cu->irb->getInt32(imm);
llvm::Value* res = GenArithOp(cu, op, rl_dest.wide, src1, src2);
DefineValue(cu, 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.
*/
static void ConvertInvoke(CompilationUnit* cu, BasicBlock* bb, MIR* mir,
InvokeType invoke_type, bool is_range, bool is_filled_new_array)
{
Codegen* cg = cu->cg.get();
CallInfo* info = cg->NewMemCallInfo(cu, bb, mir, invoke_type, is_range);
llvm::SmallVector<llvm::Value*, 10> args;
// Insert the invoke_type
args.push_back(cu->irb->getInt32(static_cast<int>(invoke_type)));
// Insert the method_idx
args.push_back(cu->irb->getInt32(info->index));
// Insert the optimization flags
args.push_back(cu->irb->getInt32(info->opt_flags));
// Now, insert the actual arguments
for (int i = 0; i < info->num_arg_words;) {
llvm::Value* val = GetLLVMValue(cu, 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.
*/
greenland::IntrinsicHelper::IntrinsicId id;
if (is_filled_new_array) {
id = greenland::IntrinsicHelper::HLFilledNewArray;
} else if (info->result.location == kLocInvalid) {
id = greenland::IntrinsicHelper::HLInvokeVoid;
} else {
if (info->result.wide) {
if (info->result.fp) {
id = greenland::IntrinsicHelper::HLInvokeDouble;
} else {
id = greenland::IntrinsicHelper::HLInvokeLong;
}
} else if (info->result.ref) {
id = greenland::IntrinsicHelper::HLInvokeObj;
} else if (info->result.fp) {
id = greenland::IntrinsicHelper::HLInvokeFloat;
} else {
id = greenland::IntrinsicHelper::HLInvokeInt;
}
}
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Value* res = cu->irb->CreateCall(intr, args);
if (info->result.location != kLocInvalid) {
DefineValue(cu, res, info->result.orig_sreg);
}
}
static void ConvertConstObject(CompilationUnit* cu, uint32_t idx,
greenland::IntrinsicHelper::IntrinsicId id, RegLocation rl_dest)
{
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Value* index = cu->irb->getInt32(idx);
llvm::Value* res = cu->irb->CreateCall(intr, index);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertCheckCast(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_src)
{
greenland::IntrinsicHelper::IntrinsicId id;
id = greenland::IntrinsicHelper::HLCheckCast;
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::SmallVector<llvm::Value*, 2> args;
args.push_back(cu->irb->getInt32(type_idx));
args.push_back(GetLLVMValue(cu, rl_src.orig_sreg));
cu->irb->CreateCall(intr, args);
}
static void ConvertNewInstance(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest)
{
greenland::IntrinsicHelper::IntrinsicId id;
id = greenland::IntrinsicHelper::NewInstance;
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Value* index = cu->irb->getInt32(type_idx);
llvm::Value* res = cu->irb->CreateCall(intr, index);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertNewArray(CompilationUnit* cu, uint32_t type_idx,
RegLocation rl_dest, RegLocation rl_src)
{
greenland::IntrinsicHelper::IntrinsicId id;
id = greenland::IntrinsicHelper::NewArray;
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::SmallVector<llvm::Value*, 2> args;
args.push_back(cu->irb->getInt32(type_idx));
args.push_back(GetLLVMValue(cu, rl_src.orig_sreg));
llvm::Value* res = cu->irb->CreateCall(intr, args);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertAget(CompilationUnit* cu, int opt_flags,
greenland::IntrinsicHelper::IntrinsicId id,
RegLocation rl_dest, RegLocation rl_array, RegLocation rl_index)
{
llvm::SmallVector<llvm::Value*, 3> args;
args.push_back(cu->irb->getInt32(opt_flags));
args.push_back(GetLLVMValue(cu, rl_array.orig_sreg));
args.push_back(GetLLVMValue(cu, rl_index.orig_sreg));
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Value* res = cu->irb->CreateCall(intr, args);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertAput(CompilationUnit* cu, int opt_flags,
greenland::IntrinsicHelper::IntrinsicId id,
RegLocation rl_src, RegLocation rl_array, RegLocation rl_index)
{
llvm::SmallVector<llvm::Value*, 4> args;
args.push_back(cu->irb->getInt32(opt_flags));
args.push_back(GetLLVMValue(cu, rl_src.orig_sreg));
args.push_back(GetLLVMValue(cu, rl_array.orig_sreg));
args.push_back(GetLLVMValue(cu, rl_index.orig_sreg));
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
cu->irb->CreateCall(intr, args);
}
static void ConvertIget(CompilationUnit* cu, int opt_flags,
greenland::IntrinsicHelper::IntrinsicId id,
RegLocation rl_dest, RegLocation rl_obj, int field_index)
{
llvm::SmallVector<llvm::Value*, 3> args;
args.push_back(cu->irb->getInt32(opt_flags));
args.push_back(GetLLVMValue(cu, rl_obj.orig_sreg));
args.push_back(cu->irb->getInt32(field_index));
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Value* res = cu->irb->CreateCall(intr, args);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertIput(CompilationUnit* cu, int opt_flags,
greenland::IntrinsicHelper::IntrinsicId id,
RegLocation rl_src, RegLocation rl_obj, int field_index)
{
llvm::SmallVector<llvm::Value*, 4> args;
args.push_back(cu->irb->getInt32(opt_flags));
args.push_back(GetLLVMValue(cu, rl_src.orig_sreg));
args.push_back(GetLLVMValue(cu, rl_obj.orig_sreg));
args.push_back(cu->irb->getInt32(field_index));
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
cu->irb->CreateCall(intr, args);
}
static void ConvertInstanceOf(CompilationUnit* cu, uint32_t type_idx,
RegLocation rl_dest, RegLocation rl_src)
{
greenland::IntrinsicHelper::IntrinsicId id;
id = greenland::IntrinsicHelper::InstanceOf;
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::SmallVector<llvm::Value*, 2> args;
args.push_back(cu->irb->getInt32(type_idx));
args.push_back(GetLLVMValue(cu, rl_src.orig_sreg));
llvm::Value* res = cu->irb->CreateCall(intr, args);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertIntToLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
{
llvm::Value* res = cu->irb->CreateSExt(GetLLVMValue(cu, rl_src.orig_sreg),
cu->irb->getInt64Ty());
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertLongToInt(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
{
llvm::Value* src = GetLLVMValue(cu, rl_src.orig_sreg);
llvm::Value* res = cu->irb->CreateTrunc(src, cu->irb->getInt32Ty());
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertFloatToDouble(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
{
llvm::Value* src = GetLLVMValue(cu, rl_src.orig_sreg);
llvm::Value* res = cu->irb->CreateFPExt(src, cu->irb->getDoubleTy());
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertDoubleToFloat(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
{
llvm::Value* src = GetLLVMValue(cu, rl_src.orig_sreg);
llvm::Value* res = cu->irb->CreateFPTrunc(src, cu->irb->getFloatTy());
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertWideComparison(CompilationUnit* cu,
greenland::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 = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::SmallVector<llvm::Value*, 2> args;
args.push_back(GetLLVMValue(cu, rl_src1.orig_sreg));
args.push_back(GetLLVMValue(cu, rl_src2.orig_sreg));
llvm::Value* res = cu->irb->CreateCall(intr, args);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertIntNarrowing(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src,
greenland::IntrinsicHelper::IntrinsicId id)
{
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Value* res =
cu->irb->CreateCall(intr, GetLLVMValue(cu, rl_src.orig_sreg));
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertNeg(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
{
llvm::Value* res = cu->irb->CreateNeg(GetLLVMValue(cu, rl_src.orig_sreg));
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertIntToFP(CompilationUnit* cu, llvm::Type* ty, RegLocation rl_dest,
RegLocation rl_src)
{
llvm::Value* res =
cu->irb->CreateSIToFP(GetLLVMValue(cu, rl_src.orig_sreg), ty);
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertFPToInt(CompilationUnit* cu, greenland::IntrinsicHelper::IntrinsicId id,
RegLocation rl_dest,
RegLocation rl_src)
{
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Value* res = cu->irb->CreateCall(intr, GetLLVMValue(cu, rl_src.orig_sreg));
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertNegFP(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
{
llvm::Value* res =
cu->irb->CreateFNeg(GetLLVMValue(cu, rl_src.orig_sreg));
DefineValue(cu, res, rl_dest.orig_sreg);
}
static void ConvertNot(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
{
llvm::Value* src = GetLLVMValue(cu, rl_src.orig_sreg);
llvm::Value* res = cu->irb->CreateXor(src, static_cast<uint64_t>(-1));
DefineValue(cu, res, rl_dest.orig_sreg);
}
/*
* Target-independent code generation. Use only high-level
* load/store utilities here, or target-dependent genXX() handlers
* when necessary.
*/
static bool ConvertMIRNode(CompilationUnit* cu, MIR* mir, BasicBlock* bb,
llvm::BasicBlock* llvm_bb, LIR* label_list)
{
bool res = false; // Assume success
RegLocation rl_src[3];
RegLocation rl_dest = 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) << 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 = oat_data_flow_attributes[opcode];
rl_src[0] = rl_src[1] = rl_src[2] = GetBadLoc();
if (attrs & DF_UA) {
if (attrs & DF_A_WIDE) {
rl_src[next_loc++] = GetSrcWide(cu, mir, next_sreg);
next_sreg+= 2;
} else {
rl_src[next_loc++] = GetSrc(cu, mir, next_sreg);
next_sreg++;
}
}
if (attrs & DF_UB) {
if (attrs & DF_B_WIDE) {
rl_src[next_loc++] = GetSrcWide(cu, mir, next_sreg);
next_sreg+= 2;
} else {
rl_src[next_loc++] = GetSrc(cu, mir, next_sreg);
next_sreg++;
}
}
if (attrs & DF_UC) {
if (attrs & DF_C_WIDE) {
rl_src[next_loc++] = GetSrcWide(cu, mir, next_sreg);
} else {
rl_src[next_loc++] = GetSrc(cu, mir, next_sreg);
}
}
if (attrs & DF_DA) {
if (attrs & DF_A_WIDE) {
rl_dest = GetDestWide(cu, mir);
} else {
rl_dest = GetDest(cu, 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(cu, rl_src[0].orig_sreg);
llvm::Value* res = EmitCopy(cu, src, rl_dest);
DefineValue(cu, res, rl_dest.orig_sreg);
}
break;
case Instruction::CONST:
case Instruction::CONST_4:
case Instruction::CONST_16: {
llvm::Constant* imm_value = cu->irb->GetJInt(vB);
llvm::Value* res = EmitConst(cu, imm_value, rl_dest);
DefineValue(cu, 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 = cu->irb->GetJLong(imm);
llvm::Value* res = EmitConst(cu, imm_value, rl_dest);
DefineValue(cu, res, rl_dest.orig_sreg);
}
break;
case Instruction::CONST_HIGH16: {
llvm::Constant* imm_value = cu->irb->GetJInt(vB << 16);
llvm::Value* res = EmitConst(cu, imm_value, rl_dest);
DefineValue(cu, res, rl_dest.orig_sreg);
}
break;
case Instruction::CONST_WIDE: {
llvm::Constant* imm_value =
cu->irb->GetJLong(mir->dalvikInsn.vB_wide);
llvm::Value* res = EmitConst(cu, imm_value, rl_dest);
DefineValue(cu, res, rl_dest.orig_sreg);
}
break;
case Instruction::CONST_WIDE_HIGH16: {
int64_t imm = static_cast<int64_t>(vB) << 48;
llvm::Constant* imm_value = cu->irb->GetJLong(imm);
llvm::Value* res = EmitConst(cu, imm_value, rl_dest);
DefineValue(cu, res, rl_dest.orig_sreg);
}
break;
case Instruction::SPUT_OBJECT:
ConvertSput(cu, vB, greenland::IntrinsicHelper::HLSputObject,
rl_src[0]);
break;
case Instruction::SPUT:
if (rl_src[0].fp) {
ConvertSput(cu, vB, greenland::IntrinsicHelper::HLSputFloat,
rl_src[0]);
} else {
ConvertSput(cu, vB, greenland::IntrinsicHelper::HLSput, rl_src[0]);
}
break;
case Instruction::SPUT_BOOLEAN:
ConvertSput(cu, vB, greenland::IntrinsicHelper::HLSputBoolean,
rl_src[0]);
break;
case Instruction::SPUT_BYTE:
ConvertSput(cu, vB, greenland::IntrinsicHelper::HLSputByte, rl_src[0]);
break;
case Instruction::SPUT_CHAR:
ConvertSput(cu, vB, greenland::IntrinsicHelper::HLSputChar, rl_src[0]);
break;
case Instruction::SPUT_SHORT:
ConvertSput(cu, vB, greenland::IntrinsicHelper::HLSputShort, rl_src[0]);
break;
case Instruction::SPUT_WIDE:
if (rl_src[0].fp) {
ConvertSput(cu, vB, greenland::IntrinsicHelper::HLSputDouble,
rl_src[0]);
} else {
ConvertSput(cu, vB, greenland::IntrinsicHelper::HLSputWide,
rl_src[0]);
}
break;
case Instruction::SGET_OBJECT:
ConvertSget(cu, vB, greenland::IntrinsicHelper::HLSgetObject, rl_dest);
break;
case Instruction::SGET:
if (rl_dest.fp) {
ConvertSget(cu, vB, greenland::IntrinsicHelper::HLSgetFloat, rl_dest);
} else {
ConvertSget(cu, vB, greenland::IntrinsicHelper::HLSget, rl_dest);
}
break;
case Instruction::SGET_BOOLEAN:
ConvertSget(cu, vB, greenland::IntrinsicHelper::HLSgetBoolean, rl_dest);
break;
case Instruction::SGET_BYTE:
ConvertSget(cu, vB, greenland::IntrinsicHelper::HLSgetByte, rl_dest);
break;
case Instruction::SGET_CHAR:
ConvertSget(cu, vB, greenland::IntrinsicHelper::HLSgetChar, rl_dest);
break;
case Instruction::SGET_SHORT:
ConvertSget(cu, vB, greenland::IntrinsicHelper::HLSgetShort, rl_dest);
break;
case Instruction::SGET_WIDE:
if (rl_dest.fp) {
ConvertSget(cu, vB, greenland::IntrinsicHelper::HLSgetDouble,
rl_dest);
} else {
ConvertSget(cu, vB, greenland::IntrinsicHelper::HLSgetWide, rl_dest);
}
break;
case Instruction::RETURN_WIDE:
case Instruction::RETURN:
case Instruction::RETURN_OBJECT: {
if (!(cu->attrs & METHOD_IS_LEAF)) {
EmitSuspendCheck(cu);
}
EmitPopShadowFrame(cu);
cu->irb->CreateRet(GetLLVMValue(cu, rl_src[0].orig_sreg));
bb->has_return = true;
}
break;
case Instruction::RETURN_VOID: {
if (!(cu->attrs & METHOD_IS_LEAF)) {
EmitSuspendCheck(cu);
}
EmitPopShadowFrame(cu);
cu->irb->CreateRetVoid();
bb->has_return = true;
}
break;
case Instruction::IF_EQ:
ConvertCompareAndBranch(cu, bb, mir, kCondEq, rl_src[0], rl_src[1]);
break;
case Instruction::IF_NE:
ConvertCompareAndBranch(cu, bb, mir, kCondNe, rl_src[0], rl_src[1]);
break;
case Instruction::IF_LT:
ConvertCompareAndBranch(cu, bb, mir, kCondLt, rl_src[0], rl_src[1]);
break;
case Instruction::IF_GE:
ConvertCompareAndBranch(cu, bb, mir, kCondGe, rl_src[0], rl_src[1]);
break;
case Instruction::IF_GT:
ConvertCompareAndBranch(cu, bb, mir, kCondGt, rl_src[0], rl_src[1]);
break;
case Instruction::IF_LE:
ConvertCompareAndBranch(cu, bb, mir, kCondLe, rl_src[0], rl_src[1]);
break;
case Instruction::IF_EQZ:
ConvertCompareZeroAndBranch(cu, bb, mir, kCondEq, rl_src[0]);
break;
case Instruction::IF_NEZ:
ConvertCompareZeroAndBranch(cu, bb, mir, kCondNe, rl_src[0]);
break;
case Instruction::IF_LTZ:
ConvertCompareZeroAndBranch(cu, bb, mir, kCondLt, rl_src[0]);
break;
case Instruction::IF_GEZ:
ConvertCompareZeroAndBranch(cu, bb, mir, kCondGe, rl_src[0]);
break;
case Instruction::IF_GTZ:
ConvertCompareZeroAndBranch(cu, bb, mir, kCondGt, rl_src[0]);
break;
case Instruction::IF_LEZ:
ConvertCompareZeroAndBranch(cu, 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(cu);
}
cu->irb->CreateBr(GetLLVMBlock(cu, bb->taken->id));
}
break;
case Instruction::ADD_LONG:
case Instruction::ADD_LONG_2ADDR:
case Instruction::ADD_INT:
case Instruction::ADD_INT_2ADDR:
ConvertArithOp(cu, 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(cu, 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(cu, 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(cu, 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(cu, 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(cu, 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(cu, 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(cu, kOpXor, rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::SHL_LONG:
case Instruction::SHL_LONG_2ADDR:
ConvertShift(cu, greenland::IntrinsicHelper::SHLLong,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::SHL_INT:
case Instruction::SHL_INT_2ADDR:
ConvertShift(cu, greenland::IntrinsicHelper::SHLInt,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::SHR_LONG:
case Instruction::SHR_LONG_2ADDR:
ConvertShift(cu, greenland::IntrinsicHelper::SHRLong,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::SHR_INT:
case Instruction::SHR_INT_2ADDR:
ConvertShift(cu, greenland::IntrinsicHelper::SHRInt,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::USHR_LONG:
case Instruction::USHR_LONG_2ADDR:
ConvertShift(cu, greenland::IntrinsicHelper::USHRLong,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::USHR_INT:
case Instruction::USHR_INT_2ADDR:
ConvertShift(cu, greenland::IntrinsicHelper::USHRInt,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::ADD_INT_LIT16:
case Instruction::ADD_INT_LIT8:
ConvertArithOpLit(cu, kOpAdd, rl_dest, rl_src[0], vC);
break;
case Instruction::RSUB_INT:
case Instruction::RSUB_INT_LIT8:
ConvertArithOpLit(cu, kOpRsub, rl_dest, rl_src[0], vC);
break;
case Instruction::MUL_INT_LIT16:
case Instruction::MUL_INT_LIT8:
ConvertArithOpLit(cu, kOpMul, rl_dest, rl_src[0], vC);
break;
case Instruction::DIV_INT_LIT16:
case Instruction::DIV_INT_LIT8:
ConvertArithOpLit(cu, kOpDiv, rl_dest, rl_src[0], vC);
break;
case Instruction::REM_INT_LIT16:
case Instruction::REM_INT_LIT8:
ConvertArithOpLit(cu, kOpRem, rl_dest, rl_src[0], vC);
break;
case Instruction::AND_INT_LIT16:
case Instruction::AND_INT_LIT8:
ConvertArithOpLit(cu, kOpAnd, rl_dest, rl_src[0], vC);
break;
case Instruction::OR_INT_LIT16:
case Instruction::OR_INT_LIT8:
ConvertArithOpLit(cu, kOpOr, rl_dest, rl_src[0], vC);
break;
case Instruction::XOR_INT_LIT16:
case Instruction::XOR_INT_LIT8:
ConvertArithOpLit(cu, kOpXor, rl_dest, rl_src[0], vC);
break;
case Instruction::SHL_INT_LIT8:
ConvertShiftLit(cu, greenland::IntrinsicHelper::SHLInt,
rl_dest, rl_src[0], vC & 0x1f);
break;
case Instruction::SHR_INT_LIT8:
ConvertShiftLit(cu, greenland::IntrinsicHelper::SHRInt,
rl_dest, rl_src[0], vC & 0x1f);
break;
case Instruction::USHR_INT_LIT8:
ConvertShiftLit(cu, greenland::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(cu, 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(cu, 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(cu, 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(cu, 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(cu, kOpRem, rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::INVOKE_STATIC:
ConvertInvoke(cu, bb, mir, kStatic, false /*range*/,
false /* NewFilledArray */);
break;
case Instruction::INVOKE_STATIC_RANGE:
ConvertInvoke(cu, bb, mir, kStatic, true /*range*/,
false /* NewFilledArray */);
break;
case Instruction::INVOKE_DIRECT:
ConvertInvoke(cu, bb, mir, kDirect, false /*range*/,
false /* NewFilledArray */);
break;
case Instruction::INVOKE_DIRECT_RANGE:
ConvertInvoke(cu, bb, mir, kDirect, true /*range*/,
false /* NewFilledArray */);
break;
case Instruction::INVOKE_VIRTUAL:
ConvertInvoke(cu, bb, mir, kVirtual, false /*range*/,
false /* NewFilledArray */);
break;
case Instruction::INVOKE_VIRTUAL_RANGE:
ConvertInvoke(cu, bb, mir, kVirtual, true /*range*/,
false /* NewFilledArray */);
break;
case Instruction::INVOKE_SUPER:
ConvertInvoke(cu, bb, mir, kSuper, false /*range*/,
false /* NewFilledArray */);
break;
case Instruction::INVOKE_SUPER_RANGE:
ConvertInvoke(cu, bb, mir, kSuper, true /*range*/,
false /* NewFilledArray */);
break;
case Instruction::INVOKE_INTERFACE:
ConvertInvoke(cu, bb, mir, kInterface, false /*range*/,
false /* NewFilledArray */);
break;
case Instruction::INVOKE_INTERFACE_RANGE:
ConvertInvoke(cu, bb, mir, kInterface, true /*range*/,
false /* NewFilledArray */);
break;
case Instruction::FILLED_NEW_ARRAY:
ConvertInvoke(cu, bb, mir, kInterface, false /*range*/,
true /* NewFilledArray */);
break;
case Instruction::FILLED_NEW_ARRAY_RANGE:
ConvertInvoke(cu, bb, mir, kInterface, true /*range*/,
true /* NewFilledArray */);
break;
case Instruction::CONST_STRING:
case Instruction::CONST_STRING_JUMBO:
ConvertConstObject(cu, vB, greenland::IntrinsicHelper::ConstString,
rl_dest);
break;
case Instruction::CONST_CLASS:
ConvertConstObject(cu, vB, greenland::IntrinsicHelper::ConstClass,
rl_dest);
break;
case Instruction::CHECK_CAST:
ConvertCheckCast(cu, vB, rl_src[0]);
break;
case Instruction::NEW_INSTANCE:
ConvertNewInstance(cu, vB, rl_dest);
break;
case Instruction::MOVE_EXCEPTION:
ConvertMoveException(cu, rl_dest);
break;
case Instruction::THROW:
ConvertThrow(cu, rl_src[0]);
/*
* If this throw is standalone, terminate.
* If it might rethrow, force termination
* of the following block.
*/
if (bb->fall_through == NULL) {
cu->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(cu, opt_flags,
greenland::IntrinsicHelper::MonitorEnter,
rl_src[0]);
break;
case Instruction::MONITOR_EXIT:
ConvertMonitorEnterExit(cu, opt_flags,
greenland::IntrinsicHelper::MonitorExit,
rl_src[0]);
break;
case Instruction::ARRAY_LENGTH:
ConvertArrayLength(cu, opt_flags, rl_dest, rl_src[0]);
break;
case Instruction::NEW_ARRAY:
ConvertNewArray(cu, vC, rl_dest, rl_src[0]);
break;
case Instruction::INSTANCE_OF:
ConvertInstanceOf(cu, vC, rl_dest, rl_src[0]);
break;
case Instruction::AGET:
if (rl_dest.fp) {
ConvertAget(cu, opt_flags,
greenland::IntrinsicHelper::HLArrayGetFloat,
rl_dest, rl_src[0], rl_src[1]);
} else {
ConvertAget(cu, opt_flags, greenland::IntrinsicHelper::HLArrayGet,
rl_dest, rl_src[0], rl_src[1]);
}
break;
case Instruction::AGET_OBJECT:
ConvertAget(cu, opt_flags, greenland::IntrinsicHelper::HLArrayGetObject,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::AGET_BOOLEAN:
ConvertAget(cu, opt_flags,
greenland::IntrinsicHelper::HLArrayGetBoolean,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::AGET_BYTE:
ConvertAget(cu, opt_flags, greenland::IntrinsicHelper::HLArrayGetByte,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::AGET_CHAR:
ConvertAget(cu, opt_flags, greenland::IntrinsicHelper::HLArrayGetChar,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::AGET_SHORT:
ConvertAget(cu, opt_flags, greenland::IntrinsicHelper::HLArrayGetShort,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::AGET_WIDE:
if (rl_dest.fp) {
ConvertAget(cu, opt_flags,
greenland::IntrinsicHelper::HLArrayGetDouble,
rl_dest, rl_src[0], rl_src[1]);
} else {
ConvertAget(cu, opt_flags, greenland::IntrinsicHelper::HLArrayGetWide,
rl_dest, rl_src[0], rl_src[1]);
}
break;
case Instruction::APUT:
if (rl_src[0].fp) {
ConvertAput(cu, opt_flags,
greenland::IntrinsicHelper::HLArrayPutFloat,
rl_src[0], rl_src[1], rl_src[2]);
} else {
ConvertAput(cu, opt_flags, greenland::IntrinsicHelper::HLArrayPut,
rl_src[0], rl_src[1], rl_src[2]);
}
break;
case Instruction::APUT_OBJECT:
ConvertAput(cu, opt_flags, greenland::IntrinsicHelper::HLArrayPutObject,
rl_src[0], rl_src[1], rl_src[2]);
break;
case Instruction::APUT_BOOLEAN:
ConvertAput(cu, opt_flags,
greenland::IntrinsicHelper::HLArrayPutBoolean,
rl_src[0], rl_src[1], rl_src[2]);
break;
case Instruction::APUT_BYTE:
ConvertAput(cu, opt_flags, greenland::IntrinsicHelper::HLArrayPutByte,
rl_src[0], rl_src[1], rl_src[2]);
break;
case Instruction::APUT_CHAR:
ConvertAput(cu, opt_flags, greenland::IntrinsicHelper::HLArrayPutChar,
rl_src[0], rl_src[1], rl_src[2]);
break;
case Instruction::APUT_SHORT:
ConvertAput(cu, opt_flags, greenland::IntrinsicHelper::HLArrayPutShort,
rl_src[0], rl_src[1], rl_src[2]);
break;
case Instruction::APUT_WIDE:
if (rl_src[0].fp) {
ConvertAput(cu, opt_flags,
greenland::IntrinsicHelper::HLArrayPutDouble,
rl_src[0], rl_src[1], rl_src[2]);
} else {
ConvertAput(cu, opt_flags, greenland::IntrinsicHelper::HLArrayPutWide,
rl_src[0], rl_src[1], rl_src[2]);
}
break;
case Instruction::IGET:
if (rl_dest.fp) {
ConvertIget(cu, opt_flags, greenland::IntrinsicHelper::HLIGetFloat,
rl_dest, rl_src[0], vC);
} else {
ConvertIget(cu, opt_flags, greenland::IntrinsicHelper::HLIGet,
rl_dest, rl_src[0], vC);
}
break;
case Instruction::IGET_OBJECT:
ConvertIget(cu, opt_flags, greenland::IntrinsicHelper::HLIGetObject,
rl_dest, rl_src[0], vC);
break;
case Instruction::IGET_BOOLEAN:
ConvertIget(cu, opt_flags, greenland::IntrinsicHelper::HLIGetBoolean,
rl_dest, rl_src[0], vC);
break;
case Instruction::IGET_BYTE:
ConvertIget(cu, opt_flags, greenland::IntrinsicHelper::HLIGetByte,
rl_dest, rl_src[0], vC);
break;
case Instruction::IGET_CHAR:
ConvertIget(cu, opt_flags, greenland::IntrinsicHelper::HLIGetChar,
rl_dest, rl_src[0], vC);
break;
case Instruction::IGET_SHORT:
ConvertIget(cu, opt_flags, greenland::IntrinsicHelper::HLIGetShort,
rl_dest, rl_src[0], vC);
break;
case Instruction::IGET_WIDE:
if (rl_dest.fp) {
ConvertIget(cu, opt_flags, greenland::IntrinsicHelper::HLIGetDouble,
rl_dest, rl_src[0], vC);
} else {
ConvertIget(cu, opt_flags, greenland::IntrinsicHelper::HLIGetWide,
rl_dest, rl_src[0], vC);
}
break;
case Instruction::IPUT:
if (rl_src[0].fp) {
ConvertIput(cu, opt_flags, greenland::IntrinsicHelper::HLIPutFloat,
rl_src[0], rl_src[1], vC);
} else {
ConvertIput(cu, opt_flags, greenland::IntrinsicHelper::HLIPut,
rl_src[0], rl_src[1], vC);
}
break;
case Instruction::IPUT_OBJECT:
ConvertIput(cu, opt_flags, greenland::IntrinsicHelper::HLIPutObject,
rl_src[0], rl_src[1], vC);
break;
case Instruction::IPUT_BOOLEAN:
ConvertIput(cu, opt_flags, greenland::IntrinsicHelper::HLIPutBoolean,
rl_src[0], rl_src[1], vC);
break;
case Instruction::IPUT_BYTE:
ConvertIput(cu, opt_flags, greenland::IntrinsicHelper::HLIPutByte,
rl_src[0], rl_src[1], vC);
break;
case Instruction::IPUT_CHAR:
ConvertIput(cu, opt_flags, greenland::IntrinsicHelper::HLIPutChar,
rl_src[0], rl_src[1], vC);
break;
case Instruction::IPUT_SHORT:
ConvertIput(cu, opt_flags, greenland::IntrinsicHelper::HLIPutShort,
rl_src[0], rl_src[1], vC);
break;
case Instruction::IPUT_WIDE:
if (rl_src[0].fp) {
ConvertIput(cu, opt_flags, greenland::IntrinsicHelper::HLIPutDouble,
rl_src[0], rl_src[1], vC);
} else {
ConvertIput(cu, opt_flags, greenland::IntrinsicHelper::HLIPutWide,
rl_src[0], rl_src[1], vC);
}
break;
case Instruction::FILL_ARRAY_DATA:
ConvertFillArrayData(cu, vB, rl_src[0]);
break;
case Instruction::LONG_TO_INT:
ConvertLongToInt(cu, rl_dest, rl_src[0]);
break;
case Instruction::INT_TO_LONG:
ConvertIntToLong(cu, rl_dest, rl_src[0]);
break;
case Instruction::INT_TO_CHAR:
ConvertIntNarrowing(cu, rl_dest, rl_src[0],
greenland::IntrinsicHelper::IntToChar);
break;
case Instruction::INT_TO_BYTE:
ConvertIntNarrowing(cu, rl_dest, rl_src[0],
greenland::IntrinsicHelper::IntToByte);
break;
case Instruction::INT_TO_SHORT:
ConvertIntNarrowing(cu, rl_dest, rl_src[0],
greenland::IntrinsicHelper::IntToShort);
break;
case Instruction::INT_TO_FLOAT:
case Instruction::LONG_TO_FLOAT:
ConvertIntToFP(cu, cu->irb->getFloatTy(), rl_dest, rl_src[0]);
break;
case Instruction::INT_TO_DOUBLE:
case Instruction::LONG_TO_DOUBLE:
ConvertIntToFP(cu, cu->irb->getDoubleTy(), rl_dest, rl_src[0]);
break;
case Instruction::FLOAT_TO_DOUBLE:
ConvertFloatToDouble(cu, rl_dest, rl_src[0]);
break;
case Instruction::DOUBLE_TO_FLOAT:
ConvertDoubleToFloat(cu, rl_dest, rl_src[0]);
break;
case Instruction::NEG_LONG:
case Instruction::NEG_INT:
ConvertNeg(cu, rl_dest, rl_src[0]);
break;
case Instruction::NEG_FLOAT:
case Instruction::NEG_DOUBLE:
ConvertNegFP(cu, rl_dest, rl_src[0]);
break;
case Instruction::NOT_LONG:
case Instruction::NOT_INT:
ConvertNot(cu, rl_dest, rl_src[0]);
break;
case Instruction::FLOAT_TO_INT:
ConvertFPToInt(cu, greenland::IntrinsicHelper::F2I, rl_dest, rl_src[0]);
break;
case Instruction::DOUBLE_TO_INT:
ConvertFPToInt(cu, greenland::IntrinsicHelper::D2I, rl_dest, rl_src[0]);
break;
case Instruction::FLOAT_TO_LONG:
ConvertFPToInt(cu, greenland::IntrinsicHelper::F2L, rl_dest, rl_src[0]);
break;
case Instruction::DOUBLE_TO_LONG:
ConvertFPToInt(cu, greenland::IntrinsicHelper::D2L, rl_dest, rl_src[0]);
break;
case Instruction::CMPL_FLOAT:
ConvertWideComparison(cu, greenland::IntrinsicHelper::CmplFloat,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::CMPG_FLOAT:
ConvertWideComparison(cu, greenland::IntrinsicHelper::CmpgFloat,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::CMPL_DOUBLE:
ConvertWideComparison(cu, greenland::IntrinsicHelper::CmplDouble,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::CMPG_DOUBLE:
ConvertWideComparison(cu, greenland::IntrinsicHelper::CmpgDouble,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::CMP_LONG:
ConvertWideComparison(cu, greenland::IntrinsicHelper::CmpLong,
rl_dest, rl_src[0], rl_src[1]);
break;
case Instruction::PACKED_SWITCH:
ConvertPackedSwitch(cu, bb, vB, rl_src[0]);
break;
case Instruction::SPARSE_SWITCH:
ConvertSparseSwitch(cu, bb, vB, rl_src[0]);
break;
default:
UNIMPLEMENTED(FATAL) << "Unsupported Dex opcode 0x" << std::hex << opcode;
res = true;
}
return res;
}
static void SetDexOffset(CompilationUnit* cu, int32_t offset)
{
cu->current_dalvik_offset = offset;
llvm::SmallVector<llvm::Value*, 1> array_ref;
array_ref.push_back(cu->irb->getInt32(offset));
llvm::MDNode* node = llvm::MDNode::get(*cu->context, array_ref);
cu->irb->SetDexOffset(node);
}
// Attach method info as metadata to special intrinsic
static void SetMethodInfo(CompilationUnit* cu)
{
// We don't want dex offset on this
cu->irb->SetDexOffset(NULL);
greenland::IntrinsicHelper::IntrinsicId id;
id = greenland::IntrinsicHelper::MethodInfo;
llvm::Function* intr = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Instruction* inst = cu->irb->CreateCall(intr);
llvm::SmallVector<llvm::Value*, 2> reg_info;
reg_info.push_back(cu->irb->getInt32(cu->num_ins));
reg_info.push_back(cu->irb->getInt32(cu->num_regs));
reg_info.push_back(cu->irb->getInt32(cu->num_outs));
reg_info.push_back(cu->irb->getInt32(cu->num_compiler_temps));
reg_info.push_back(cu->irb->getInt32(cu->num_ssa_regs));
llvm::MDNode* reg_info_node = llvm::MDNode::get(*cu->context, reg_info);
inst->setMetadata("RegInfo", reg_info_node);
int promo_size = cu->num_dalvik_registers + cu->num_compiler_temps + 1;
llvm::SmallVector<llvm::Value*, 50> pmap;
for (int i = 0; i < promo_size; i++) {
PromotionMap* p = &cu->promotion_map[i];
int32_t map_data = ((p->first_in_pair & 0xff) << 24) |
((p->FpReg & 0xff) << 16) |
((p->core_reg & 0xff) << 8) |
((p->fp_location & 0xf) << 4) |
(p->core_location & 0xf);
pmap.push_back(cu->irb->getInt32(map_data));
}
llvm::MDNode* map_node = llvm::MDNode::get(*cu->context, pmap);
inst->setMetadata("PromotionMap", map_node);
SetDexOffset(cu, cu->current_dalvik_offset);
}
static void HandlePhiNodes(CompilationUnit* cu, BasicBlock* bb, llvm::BasicBlock* llvm_bb)
{
SetDexOffset(cu, 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 = cu->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(cu, rl_dest);
llvm::PHINode* phi = cu->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 = GetRawSrc(cu, 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 = cu->block_id_map.find(incoming[i]);
DCHECK(it != cu->block_id_map.end());
DCHECK(GetLLVMValue(cu, loc.orig_sreg) != NULL);
DCHECK(GetLLVMBlock(cu, it->second) != NULL);
phi->addIncoming(GetLLVMValue(cu, loc.orig_sreg),
GetLLVMBlock(cu, it->second));
}
DefineValueOnly(cu, phi, rl_dest.orig_sreg);
}
}
/* Extended MIR instructions like PHI */
static void ConvertExtendedMIR(CompilationUnit* cu, 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 = cu->reg_location[mir->ssa_rep->defs[0]];
if (!rl_dest.high_word) {
// Only consider low word of pairs.
DCHECK(GetLLVMValue(cu, rl_dest.orig_sreg) != NULL);
llvm::Value* phi = GetLLVMValue(cu, rl_dest.orig_sreg);
if (1) SetVregOnValue(cu, 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)) {
cu->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 */
static bool BlockBitcodeConversion(CompilationUnit* cu, BasicBlock* bb)
{
if (bb->block_type == kDead) return false;
llvm::BasicBlock* llvm_bb = GetLLVMBlock(cu, bb->id);
if (llvm_bb == NULL) {
CHECK(bb->block_type == kExitBlock);
} else {
cu->irb->SetInsertPoint(llvm_bb);
SetDexOffset(cu, 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(cu);
{ // Allocate shadowframe.
greenland::IntrinsicHelper::IntrinsicId id =
greenland::IntrinsicHelper::AllocaShadowFrame;
llvm::Function* func = cu->intrinsic_helper->GetIntrinsicFunction(id);
llvm::Value* entries = cu->irb->getInt32(cu->num_dalvik_registers);
cu->irb->CreateCall(func, entries);
}
{ // Store arguments to vregs.
uint16_t arg_reg = cu->num_regs;
llvm::Function::arg_iterator arg_iter(cu->func->arg_begin());
llvm::Function::arg_iterator arg_end(cu->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(cu, arg_iter, arg_reg);
++arg_iter;
++arg_reg;
}
for (uint32_t i = 1; i < shorty_size; ++i, ++arg_iter) {
SetVregOnValue(cu, 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(cu, bb, llvm_bb);
for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
SetDexOffset(cu, 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 = cu->intrinsic_helper->GetIntrinsicFunction(
greenland::IntrinsicHelper::CatchTargets);
llvm::Value* switch_key =
cu->irb->CreateCall(intr, cu->irb->getInt32(mir->offset));
GrowableListIterator iter;
GrowableListIteratorInit(&bb->successor_block_list.blocks, &iter);
// New basic block to use for work half
llvm::BasicBlock* work_bb =
llvm::BasicBlock::Create(*cu->context, "", cu->func);
llvm::SwitchInst* sw =
cu->irb->CreateSwitch(switch_key, work_bb,
bb->successor_block_list.blocks.num_used);
while (true) {
SuccessorBlockInfo *successor_block_info =
reinterpret_cast<SuccessorBlockInfo*>(GrowableListIteratorNext(&iter));
if (successor_block_info == NULL) break;
llvm::BasicBlock *target =
GetLLVMBlock(cu, successor_block_info->block->id);
int type_index = successor_block_info->key;
sw->addCase(cu->irb->getInt32(type_index), target);
}
llvm_bb = work_bb;
cu->irb->SetInsertPoint(llvm_bb);
}
}
if (opcode >= kMirOpFirst) {
ConvertExtendedMIR(cu, bb, mir, llvm_bb);
continue;
}
bool not_handled = ConvertMIRNode(cu, mir, bb, llvm_bb,
NULL /* label_list */);
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) {
cu->entryTarget_bb = GetLLVMBlock(cu, bb->fall_through->id);
} else if ((bb->fall_through != NULL) && !bb->has_return) {
cu->irb->CreateBr(GetLLVMBlock(cu, 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;
}
static llvm::FunctionType* GetFunctionType(CompilationUnit* cu) {
// Get return type
llvm::Type* ret_type = cu->irb->GetJType(RemapShorty(cu->shorty[0]),
greenland::kAccurate);
// Get argument type
std::vector<llvm::Type*> args_type;
// method object
args_type.push_back(cu->irb->GetJMethodTy());
// Do we have a "this"?
if ((cu->access_flags & kAccStatic) == 0) {
args_type.push_back(cu->irb->GetJObjectTy());
}
for (uint32_t i = 1; i < strlen(cu->shorty); ++i) {
args_type.push_back(cu->irb->GetJType(RemapShorty(cu->shorty[i]),
greenland::kAccurate));
}
return llvm::FunctionType::get(ret_type, args_type, false);
}
static bool CreateFunction(CompilationUnit* cu) {
std::string func_name(PrettyMethod(cu->method_idx, *cu->dex_file,
/* with_signature */ false));
llvm::FunctionType* func_type = GetFunctionType(cu);
if (func_type == NULL) {
return false;
}
cu->func = llvm::Function::Create(func_type,
llvm::Function::ExternalLinkage,
func_name, cu->module);
llvm::Function::arg_iterator arg_iter(cu->func->arg_begin());
llvm::Function::arg_iterator arg_end(cu->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 += cu->reg_location[start_sreg].wide ? 2 : 1;
}
return true;
}
static bool CreateLLVMBasicBlock(CompilationUnit* cu, BasicBlock* bb)
{
// Skip the exit block
if ((bb->block_type == kDead) ||(bb->block_type == kExitBlock)) {
cu->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(*cu->context, entry_block ? "entry" :
StringPrintf(kLabelFormat, bb->catch_entry ? kCatchBlock :
kNormalBlock, offset, bb->id), cu->func);
if (entry_block) {
cu->entry_bb = llvm_bb;
cu->placeholder_bb =
llvm::BasicBlock::Create(*cu->context, "placeholder",
cu->func);
}
cu->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 MethodMIR2Bitcode(CompilationUnit* cu)
{
InitIR(cu);
CompilerInitGrowableList(cu, &cu->llvm_values, cu->num_ssa_regs);
// Create the function
CreateFunction(cu);
// Create an LLVM basic block for each MIR block in dfs preorder
DataFlowAnalysisDispatcher(cu, CreateLLVMBasicBlock,
kPreOrderDFSTraversal, false /* is_iterative */);
/*
* 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).
*/
cu->irb->SetInsertPoint(cu->placeholder_bb);
llvm::Function::arg_iterator arg_iter(cu->func->arg_begin());
arg_iter++; /* Skip path method */
for (int i = 0; i < cu->num_ssa_regs; i++) {
llvm::Value* val;
RegLocation rl_temp = cu->reg_location[i];
if ((SRegToVReg(cu, i) < 0) || rl_temp.high_word) {
InsertGrowableList(cu, &cu->llvm_values, 0);
} else if ((i < cu->num_regs) ||
(i >= (cu->num_regs + cu->num_ins))) {
llvm::Constant* imm_value = cu->reg_location[i].wide ?
cu->irb->GetJLong(0) : cu->irb->GetJInt(0);
val = EmitConst(cu, imm_value, cu->reg_location[i]);
val->setName(LlvmSSAName(cu, i));
InsertGrowableList(cu, &cu->llvm_values, reinterpret_cast<uintptr_t>(val));
} else {
// Recover previously-created argument values
llvm::Value* arg_val = arg_iter++;
InsertGrowableList(cu, &cu->llvm_values, reinterpret_cast<uintptr_t>(arg_val));
}
}
DataFlowAnalysisDispatcher(cu, BlockBitcodeConversion,
kPreOrderDFSTraversal, false /* Iterative */);
/*
* 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 = cu->placeholder_bb->begin(),
it_end = cu->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(cu, 0);
if (cu->placeholder_bb->empty()) {
cu->placeholder_bb->eraseFromParent();
} else {
cu->irb->SetInsertPoint(cu->placeholder_bb);
cu->irb->CreateBr(cu->entryTarget_bb);
cu->entryTarget_bb = cu->placeholder_bb;
}
cu->irb->SetInsertPoint(cu->entry_bb);
cu->irb->CreateBr(cu->entryTarget_bb);
if (cu->enable_debug & (1 << kDebugVerifyBitcode)) {
if (llvm::verifyFunction(*cu->func, llvm::PrintMessageAction)) {
LOG(INFO) << "Bitcode verification FAILED for "
<< PrettyMethod(cu->method_idx, *cu->dex_file)
<< " of size " << cu->insns_size;
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));
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(cu->module, out_file->os());
out_file->keep();
}
}
static RegLocation GetLoc(CompilationUnit* cu, llvm::Value* val) {
RegLocation res;
DCHECK(val != NULL);
SafeMap<llvm::Value*, RegLocation>::iterator it = cu->loc_map.find(val);
if (it == cu->loc_map.end()) {
std::string val_name = val->getName().str();
if (val_name.empty()) {
// FIXME: need to be more robust, handle FP and be in a position to
// manage unnamed temps whose lifetimes span basic block boundaries
UNIMPLEMENTED(WARNING) << "Need to handle unnamed llvm temps";
memset(&res, 0, sizeof(res));
res.location = kLocPhysReg;
res.low_reg = AllocTemp(cu);
res.home = true;
res.s_reg_low = INVALID_SREG;
res.orig_sreg = INVALID_SREG;
llvm::Type* ty = val->getType();
res.wide = ((ty == cu->irb->getInt64Ty()) ||
(ty == cu->irb->getDoubleTy()));
if (res.wide) {
res.high_reg = AllocTemp(cu);
}
cu->loc_map.Put(val, res);
} else {
DCHECK_EQ(val_name[0], 'v');
int base_sreg = INVALID_SREG;
sscanf(val_name.c_str(), "v%d_", &base_sreg);
res = cu->reg_location[base_sreg];
cu->loc_map.Put(val, res);
}
} else {
res = it->second;
}
return res;
}
static Instruction::Code GetDalvikOpcode(OpKind op, bool is_const, bool is_wide)
{
Instruction::Code res = Instruction::NOP;
if (is_wide) {
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 (is_const){
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;
}
static Instruction::Code GetDalvikFPOpcode(OpKind op, bool is_const, bool is_wide)
{
Instruction::Code res = Instruction::NOP;
if (is_wide) {
switch(op) {
case kOpAdd: res = Instruction::ADD_DOUBLE; break;
case kOpSub: res = Instruction::SUB_DOUBLE; break;
case kOpMul: res = Instruction::MUL_DOUBLE; break;
case kOpDiv: res = Instruction::DIV_DOUBLE; break;
case kOpRem: res = Instruction::REM_DOUBLE; break;
default: LOG(FATAL) << "Unexpected OpKind " << op;
}
} else {
switch(op) {
case kOpAdd: res = Instruction::ADD_FLOAT; break;
case kOpSub: res = Instruction::SUB_FLOAT; break;
case kOpMul: res = Instruction::MUL_FLOAT; break;
case kOpDiv: res = Instruction::DIV_FLOAT; break;
case kOpRem: res = Instruction::REM_FLOAT; break;
default: LOG(FATAL) << "Unexpected OpKind " << op;
}
}
return res;
}
static void CvtBinFPOp(CompilationUnit* cu, OpKind op, llvm::Instruction* inst)
{
Codegen* cg = cu->cg.get();
RegLocation rl_dest = GetLoc(cu, inst);
/*
* Normally, we won't ever generate an FP operation with an immediate
* operand (not supported in Dex instruction set). However, the IR builder
* may insert them - in particular for create_neg_fp. Recognize this case
* and deal with it.
*/
llvm::ConstantFP* op1C = llvm::dyn_cast<llvm::ConstantFP>(inst->getOperand(0));
llvm::ConstantFP* op2C = llvm::dyn_cast<llvm::ConstantFP>(inst->getOperand(1));
DCHECK(op2C == NULL);
if ((op1C != NULL) && (op == kOpSub)) {
RegLocation rl_src = GetLoc(cu, inst->getOperand(1));
if (rl_dest.wide) {
cg->GenArithOpDouble(cu, Instruction::NEG_DOUBLE, rl_dest, rl_src, rl_src);
} else {
cg->GenArithOpFloat(cu, Instruction::NEG_FLOAT, rl_dest, rl_src, rl_src);
}
} else {
DCHECK(op1C == NULL);
RegLocation rl_src1 = GetLoc(cu, inst->getOperand(0));
RegLocation rl_src2 = GetLoc(cu, inst->getOperand(1));
Instruction::Code dalvik_op = GetDalvikFPOpcode(op, false, rl_dest.wide);
if (rl_dest.wide) {
cg->GenArithOpDouble(cu, dalvik_op, rl_dest, rl_src1, rl_src2);
} else {
cg->GenArithOpFloat(cu, dalvik_op, rl_dest, rl_src1, rl_src2);
}
}
}
static void CvtIntNarrowing(CompilationUnit* cu, llvm::Instruction* inst,
Instruction::Code opcode)
{
Codegen* cg = cu->cg.get();
RegLocation rl_dest = GetLoc(cu, inst);
RegLocation rl_src = GetLoc(cu, inst->getOperand(0));
cg->GenIntNarrowing(cu, opcode, rl_dest, rl_src);
}
static void CvtIntToFP(CompilationUnit* cu, llvm::Instruction* inst)
{
Codegen* cg = cu->cg.get();
RegLocation rl_dest = GetLoc(cu, inst);
RegLocation rl_src = GetLoc(cu, inst->getOperand(0));
Instruction::Code opcode;
if (rl_dest.wide) {
if (rl_src.wide) {
opcode = Instruction::LONG_TO_DOUBLE;
} else {
opcode = Instruction::INT_TO_DOUBLE;
}
} else {
if (rl_src.wide) {
opcode = Instruction::LONG_TO_FLOAT;
} else {
opcode = Instruction::INT_TO_FLOAT;
}
}
cg->GenConversion(cu, opcode, rl_dest, rl_src);
}
static void CvtFPToInt(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
RegLocation rl_dest = GetLoc(cu, call_inst);
RegLocation rl_src = GetLoc(cu, call_inst->getOperand(0));
Instruction::Code opcode;
if (rl_dest.wide) {
if (rl_src.wide) {
opcode = Instruction::DOUBLE_TO_LONG;
} else {
opcode = Instruction::FLOAT_TO_LONG;
}
} else {
if (rl_src.wide) {
opcode = Instruction::DOUBLE_TO_INT;
} else {
opcode = Instruction::FLOAT_TO_INT;
}
}
cg->GenConversion(cu, opcode, rl_dest, rl_src);
}
static void CvtFloatToDouble(CompilationUnit* cu, llvm::Instruction* inst)
{
Codegen* cg = cu->cg.get();
RegLocation rl_dest = GetLoc(cu, inst);
RegLocation rl_src = GetLoc(cu, inst->getOperand(0));
cg->GenConversion(cu, Instruction::FLOAT_TO_DOUBLE, rl_dest, rl_src);
}
static void CvtTrunc(CompilationUnit* cu, llvm::Instruction* inst)
{
Codegen* cg = cu->cg.get();
RegLocation rl_dest = GetLoc(cu, inst);
RegLocation rl_src = GetLoc(cu, inst->getOperand(0));
rl_src = UpdateLocWide(cu, rl_src);
rl_src = WideToNarrow(cu, rl_src);
cg->StoreValue(cu, rl_dest, rl_src);
}
static void CvtDoubleToFloat(CompilationUnit* cu, llvm::Instruction* inst)
{
Codegen* cg = cu->cg.get();
RegLocation rl_dest = GetLoc(cu, inst);
RegLocation rl_src = GetLoc(cu, inst->getOperand(0));
cg->GenConversion(cu, Instruction::DOUBLE_TO_FLOAT, rl_dest, rl_src);
}
static void CvtIntExt(CompilationUnit* cu, llvm::Instruction* inst, bool is_signed)
{
Codegen* cg = cu->cg.get();
// TODO: evaluate src/tgt types and add general support for more than int to long
RegLocation rl_dest = GetLoc(cu, inst);
RegLocation rl_src = GetLoc(cu, inst->getOperand(0));
DCHECK(rl_dest.wide);
DCHECK(!rl_src.wide);
DCHECK(!rl_dest.fp);
DCHECK(!rl_src.fp);
RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
if (rl_src.location == kLocPhysReg) {
cg->OpRegCopy(cu, rl_result.low_reg, rl_src.low_reg);
} else {
cg->LoadValueDirect(cu, rl_src, rl_result.low_reg);
}
if (is_signed) {
cg->OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_result.low_reg, 31);
} else {
cg->LoadConstant(cu, rl_result.high_reg, 0);
}
cg->StoreValueWide(cu, rl_dest, rl_result);
}
static void CvtBinOp(CompilationUnit* cu, OpKind op, llvm::Instruction* inst)
{
Codegen* cg = cu->cg.get();
RegLocation rl_dest = GetLoc(cu, inst);
llvm::Value* lhs = inst->getOperand(0);
// Special-case RSUB/NEG
llvm::ConstantInt* lhs_imm = llvm::dyn_cast<llvm::ConstantInt>(lhs);
if ((op == kOpSub) && (lhs_imm != NULL)) {
RegLocation rl_src1 = GetLoc(cu, inst->getOperand(1));
if (rl_src1.wide) {
DCHECK_EQ(lhs_imm->getSExtValue(), 0);
cg->GenArithOpLong(cu, Instruction::NEG_LONG, rl_dest, rl_src1, rl_src1);
} else {
cg->GenArithOpIntLit(cu, Instruction::RSUB_INT, rl_dest, rl_src1,
lhs_imm->getSExtValue());
}
return;
}
DCHECK(lhs_imm == NULL);
RegLocation rl_src1 = GetLoc(cu, inst->getOperand(0));
llvm::Value* rhs = inst->getOperand(1);
llvm::ConstantInt* const_rhs = llvm::dyn_cast<llvm::ConstantInt>(rhs);
if (!rl_dest.wide && (const_rhs != NULL)) {
Instruction::Code dalvik_op = GetDalvikOpcode(op, true, false);
cg->GenArithOpIntLit(cu, dalvik_op, rl_dest, rl_src1, const_rhs->getSExtValue());
} else {
Instruction::Code dalvik_op = GetDalvikOpcode(op, false, rl_dest.wide);
RegLocation rl_src2;
if (const_rhs != NULL) {
// ir_builder converts NOT_LONG to xor src, -1. Restore
DCHECK_EQ(dalvik_op, Instruction::XOR_LONG);
DCHECK_EQ(-1L, const_rhs->getSExtValue());
dalvik_op = Instruction::NOT_LONG;
rl_src2 = rl_src1;
} else {
rl_src2 = GetLoc(cu, rhs);
}
if (rl_dest.wide) {
cg->GenArithOpLong(cu, dalvik_op, rl_dest, rl_src1, rl_src2);
} else {
cg->GenArithOpInt(cu, dalvik_op, rl_dest, rl_src1, rl_src2);
}
}
}
static void CvtShiftOp(CompilationUnit* cu, Instruction::Code opcode, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 2U);
RegLocation rl_dest = GetLoc(cu, call_inst);
RegLocation rl_src = GetLoc(cu, call_inst->getArgOperand(0));
llvm::Value* rhs = call_inst->getArgOperand(1);
if (llvm::ConstantInt* src2 = llvm::dyn_cast<llvm::ConstantInt>(rhs)) {
DCHECK(!rl_dest.wide);
cg->GenArithOpIntLit(cu, opcode, rl_dest, rl_src, src2->getSExtValue());
} else {
RegLocation rl_shift = GetLoc(cu, rhs);
if (call_inst->getType() == cu->irb->getInt64Ty()) {
cg->GenShiftOpLong(cu, opcode, rl_dest, rl_src, rl_shift);
} else {
cg->GenArithOpInt(cu, opcode, rl_dest, rl_src, rl_shift);
}
}
}
static void CvtBr(CompilationUnit* cu, llvm::Instruction* inst)
{
Codegen* cg = cu->cg.get();
llvm::BranchInst* br_inst = llvm::dyn_cast<llvm::BranchInst>(inst);
DCHECK(br_inst != NULL);
DCHECK(br_inst->isUnconditional()); // May change - but this is all we use now
llvm::BasicBlock* target_bb = br_inst->getSuccessor(0);
cg->OpUnconditionalBranch(cu, cu->block_to_label_map.Get(target_bb));
}
static void CvtPhi(CompilationUnit* cu, llvm::Instruction* inst)
{
// Nop - these have already been processed
}
static void CvtRet(CompilationUnit* cu, llvm::Instruction* inst)
{
Codegen* cg = cu->cg.get();
llvm::ReturnInst* ret_inst = llvm::dyn_cast<llvm::ReturnInst>(inst);
llvm::Value* ret_val = ret_inst->getReturnValue();
if (ret_val != NULL) {
RegLocation rl_src = GetLoc(cu, ret_val);
if (rl_src.wide) {
cg->StoreValueWide(cu, GetReturnWide(cu, rl_src.fp), rl_src);
} else {
cg->StoreValue(cu, GetReturn(cu, rl_src.fp), rl_src);
}
}
cg->GenExitSequence(cu);
}
static ConditionCode GetCond(llvm::ICmpInst::Predicate llvm_cond)
{
ConditionCode res = kCondAl;
switch(llvm_cond) {
case llvm::ICmpInst::ICMP_EQ: res = kCondEq; break;
case llvm::ICmpInst::ICMP_NE: res = kCondNe; break;
case llvm::ICmpInst::ICMP_SLT: res = kCondLt; break;
case llvm::ICmpInst::ICMP_SGE: res = kCondGe; break;
case llvm::ICmpInst::ICMP_SGT: res = kCondGt; break;
case llvm::ICmpInst::ICMP_SLE: res = kCondLe; break;
default: LOG(FATAL) << "Unexpected llvm condition";
}
return res;
}
static void CvtICmp(CompilationUnit* cu, llvm::Instruction* inst)
{
// cg->GenCmpLong(cu, rl_dest, rl_src1, rl_src2)
UNIMPLEMENTED(FATAL);
}
static void CvtICmpBr(CompilationUnit* cu, llvm::Instruction* inst,
llvm::BranchInst* br_inst)
{
Codegen* cg = cu->cg.get();
// Get targets
llvm::BasicBlock* taken_bb = br_inst->getSuccessor(0);
LIR* taken = cu->block_to_label_map.Get(taken_bb);
llvm::BasicBlock* fallthrough_bb = br_inst->getSuccessor(1);
LIR* fall_through = cu->block_to_label_map.Get(fallthrough_bb);
// Get comparison operands
llvm::ICmpInst* i_cmp_inst = llvm::dyn_cast<llvm::ICmpInst>(inst);
ConditionCode cond = GetCond(i_cmp_inst->getPredicate());
llvm::Value* lhs = i_cmp_inst->getOperand(0);
// Not expecting a constant as 1st operand
DCHECK(llvm::dyn_cast<llvm::ConstantInt>(lhs) == NULL);
RegLocation rl_src1 = GetLoc(cu, inst->getOperand(0));
rl_src1 = cg->LoadValue(cu, rl_src1, kCoreReg);
llvm::Value* rhs = inst->getOperand(1);
if (cu->instruction_set == kMips) {
// Compare and branch in one shot
UNIMPLEMENTED(FATAL);
}
//Compare, then branch
// TODO: handle fused CMP_LONG/IF_xxZ case
if (llvm::ConstantInt* src2 = llvm::dyn_cast<llvm::ConstantInt>(rhs)) {
cg->OpRegImm(cu, kOpCmp, rl_src1.low_reg, src2->getSExtValue());
} else if (llvm::dyn_cast<llvm::ConstantPointerNull>(rhs) != NULL) {
cg->OpRegImm(cu, kOpCmp, rl_src1.low_reg, 0);
} else {
RegLocation rl_src2 = GetLoc(cu, rhs);
rl_src2 = cg->LoadValue(cu, rl_src2, kCoreReg);
cg->OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
}
cg->OpCondBranch(cu, cond, taken);
// Fallthrough
cg->OpUnconditionalBranch(cu, fall_through);
}
static void CvtCopy(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 1U);
RegLocation rl_src = GetLoc(cu, call_inst->getArgOperand(0));
RegLocation rl_dest = GetLoc(cu, call_inst);
DCHECK_EQ(rl_src.wide, rl_dest.wide);
DCHECK_EQ(rl_src.fp, rl_dest.fp);
if (rl_src.wide) {
cg->StoreValueWide(cu, rl_dest, rl_src);
} else {
cg->StoreValue(cu, rl_dest, rl_src);
}
}
// Note: Immediate arg is a ConstantInt regardless of result type
static void CvtConst(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 1U);
llvm::ConstantInt* src =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
uint64_t immval = src->getZExtValue();
RegLocation rl_dest = GetLoc(cu, call_inst);
RegLocation rl_result = EvalLoc(cu, rl_dest, kAnyReg, true);
if (rl_dest.wide) {
cg->LoadConstantValueWide(cu, rl_result.low_reg, rl_result.high_reg,
(immval) & 0xffffffff, (immval >> 32) & 0xffffffff);
cg->StoreValueWide(cu, rl_dest, rl_result);
} else {
int immediate = immval & 0xffffffff;
cg->LoadConstantNoClobber(cu, rl_result.low_reg, immediate);
cg->StoreValue(cu, rl_dest, rl_result);
if (immediate == 0) {
cg->Workaround7250540(cu, rl_dest, rl_result.low_reg);
}
}
}
static void CvtConstObject(CompilationUnit* cu, llvm::CallInst* call_inst, bool is_string)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 1U);
llvm::ConstantInt* idx_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
uint32_t index = idx_val->getZExtValue();
RegLocation rl_dest = GetLoc(cu, call_inst);
if (is_string) {
cg->GenConstString(cu, index, rl_dest);
} else {
cg->GenConstClass(cu, index, rl_dest);
}
}
static void CvtFillArrayData(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 2U);
llvm::ConstantInt* offset_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
RegLocation rl_src = GetLoc(cu, call_inst->getArgOperand(1));
cg->GenFillArrayData(cu, offset_val->getSExtValue(), rl_src);
}
static void CvtNewInstance(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 1U);
llvm::ConstantInt* type_idx_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
uint32_t type_idx = type_idx_val->getZExtValue();
RegLocation rl_dest = GetLoc(cu, call_inst);
cg->GenNewInstance(cu, type_idx, rl_dest);
}
static void CvtNewArray(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 2U);
llvm::ConstantInt* type_idx_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
uint32_t type_idx = type_idx_val->getZExtValue();
llvm::Value* len = call_inst->getArgOperand(1);
RegLocation rl_len = GetLoc(cu, len);
RegLocation rl_dest = GetLoc(cu, call_inst);
cg->GenNewArray(cu, type_idx, rl_dest, rl_len);
}
static void CvtInstanceOf(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 2U);
llvm::ConstantInt* type_idx_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
uint32_t type_idx = type_idx_val->getZExtValue();
llvm::Value* src = call_inst->getArgOperand(1);
RegLocation rl_src = GetLoc(cu, src);
RegLocation rl_dest = GetLoc(cu, call_inst);
cg->GenInstanceof(cu, type_idx, rl_dest, rl_src);
}
static void CvtThrow(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 1U);
llvm::Value* src = call_inst->getArgOperand(0);
RegLocation rl_src = GetLoc(cu, src);
cg->GenThrow(cu, rl_src);
}
static void CvtMonitorEnterExit(CompilationUnit* cu, bool is_enter,
llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 2U);
llvm::ConstantInt* opt_flags =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
llvm::Value* src = call_inst->getArgOperand(1);
RegLocation rl_src = GetLoc(cu, src);
if (is_enter) {
cg->GenMonitorEnter(cu, opt_flags->getZExtValue(), rl_src);
} else {
cg->GenMonitorExit(cu, opt_flags->getZExtValue(), rl_src);
}
}
static void CvtArrayLength(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 2U);
llvm::ConstantInt* opt_flags =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
llvm::Value* src = call_inst->getArgOperand(1);
RegLocation rl_src = GetLoc(cu, src);
rl_src = cg->LoadValue(cu, rl_src, kCoreReg);
cg->GenNullCheck(cu, rl_src.s_reg_low, rl_src.low_reg, opt_flags->getZExtValue());
RegLocation rl_dest = GetLoc(cu, call_inst);
RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
int len_offset = Array::LengthOffset().Int32Value();
cg->LoadWordDisp(cu, rl_src.low_reg, len_offset, rl_result.low_reg);
cg->StoreValue(cu, rl_dest, rl_result);
}
static void CvtMoveException(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
RegLocation rl_dest = GetLoc(cu, call_inst);
cg->GenMoveException(cu, rl_dest);
}
static void CvtSget(CompilationUnit* cu, llvm::CallInst* call_inst, bool is_wide, bool is_object)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 1U);
llvm::ConstantInt* type_idx_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
uint32_t type_idx = type_idx_val->getZExtValue();
RegLocation rl_dest = GetLoc(cu, call_inst);
cg->GenSget(cu, type_idx, rl_dest, is_wide, is_object);
}
static void CvtSput(CompilationUnit* cu, llvm::CallInst* call_inst, bool is_wide, bool is_object)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 2U);
llvm::ConstantInt* type_idx_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
uint32_t type_idx = type_idx_val->getZExtValue();
llvm::Value* src = call_inst->getArgOperand(1);
RegLocation rl_src = GetLoc(cu, src);
cg->GenSput(cu, type_idx, rl_src, is_wide, is_object);
}
static void CvtAget(CompilationUnit* cu, llvm::CallInst* call_inst, OpSize size, int scale)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 3U);
llvm::ConstantInt* opt_flags =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
RegLocation rl_array = GetLoc(cu, call_inst->getArgOperand(1));
RegLocation rl_index = GetLoc(cu, call_inst->getArgOperand(2));
RegLocation rl_dest = GetLoc(cu, call_inst);
cg->GenArrayGet(cu, opt_flags->getZExtValue(), size, rl_array, rl_index,
rl_dest, scale);
}
static void CvtAput(CompilationUnit* cu, llvm::CallInst* call_inst, OpSize size,
int scale, bool is_object)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 4U);
llvm::ConstantInt* opt_flags =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
RegLocation rl_src = GetLoc(cu, call_inst->getArgOperand(1));
RegLocation rl_array = GetLoc(cu, call_inst->getArgOperand(2));
RegLocation rl_index = GetLoc(cu, call_inst->getArgOperand(3));
if (is_object) {
cg->GenArrayObjPut(cu, opt_flags->getZExtValue(), rl_array, rl_index,
rl_src, scale);
} else {
cg->GenArrayPut(cu, opt_flags->getZExtValue(), size, rl_array, rl_index,
rl_src, scale);
}
}
static void CvtAputObj(CompilationUnit* cu, llvm::CallInst* call_inst)
{
CvtAput(cu, call_inst, kWord, 2, true /* is_object */);
}
static void CvtAputPrimitive(CompilationUnit* cu, llvm::CallInst* call_inst,
OpSize size, int scale)
{
CvtAput(cu, call_inst, size, scale, false /* is_object */);
}
static void CvtIget(CompilationUnit* cu, llvm::CallInst* call_inst, OpSize size,
bool is_wide, bool is_obj)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 3U);
llvm::ConstantInt* opt_flags =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
RegLocation rl_obj = GetLoc(cu, call_inst->getArgOperand(1));
llvm::ConstantInt* field_idx =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(2));
RegLocation rl_dest = GetLoc(cu, call_inst);
cg->GenIGet(cu, field_idx->getZExtValue(), opt_flags->getZExtValue(),
size, rl_dest, rl_obj, is_wide, is_obj);
}
static void CvtIput(CompilationUnit* cu, llvm::CallInst* call_inst, OpSize size,
bool is_wide, bool is_obj)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 4U);
llvm::ConstantInt* opt_flags =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
RegLocation rl_src = GetLoc(cu, call_inst->getArgOperand(1));
RegLocation rl_obj = GetLoc(cu, call_inst->getArgOperand(2));
llvm::ConstantInt* field_idx =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(3));
cg->GenIPut(cu, field_idx->getZExtValue(), opt_flags->getZExtValue(),
size, rl_src, rl_obj, is_wide, is_obj);
}
static void CvtCheckCast(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
DCHECK_EQ(call_inst->getNumArgOperands(), 2U);
llvm::ConstantInt* type_idx =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
RegLocation rl_src = GetLoc(cu, call_inst->getArgOperand(1));
cg->GenCheckCast(cu, type_idx->getZExtValue(), rl_src);
}
static void CvtFPCompare(CompilationUnit* cu, llvm::CallInst* call_inst,
Instruction::Code opcode)
{
Codegen* cg = cu->cg.get();
RegLocation rl_src1 = GetLoc(cu, call_inst->getArgOperand(0));
RegLocation rl_src2 = GetLoc(cu, call_inst->getArgOperand(1));
RegLocation rl_dest = GetLoc(cu, call_inst);
cg->GenCmpFP(cu, opcode, rl_dest, rl_src1, rl_src2);
}
static void CvtLongCompare(CompilationUnit* cu, llvm::CallInst* call_inst)
{
Codegen* cg = cu->cg.get();
RegLocation rl_src1 = GetLoc(cu, call_inst->getArgOperand(0));
RegLocation rl_src2 = GetLoc(cu, call_inst->getArgOperand(1));
RegLocation rl_dest = GetLoc(cu, call_inst);
cg->GenCmpLong(cu, rl_dest, rl_src1, rl_src2);
}
static void CvtSwitch(CompilationUnit* cu, llvm::Instruction* inst)
{
Codegen* cg = cu->cg.get();
llvm::SwitchInst* sw_inst = llvm::dyn_cast<llvm::SwitchInst>(inst);
DCHECK(sw_inst != NULL);
llvm::Value* test_val = sw_inst->getCondition();
llvm::MDNode* table_offset_node = sw_inst->getMetadata("SwitchTable");
DCHECK(table_offset_node != NULL);
llvm::ConstantInt* table_offset_value =
static_cast<llvm::ConstantInt*>(table_offset_node->getOperand(0));
int32_t table_offset = table_offset_value->getSExtValue();
RegLocation rl_src = GetLoc(cu, test_val);
const uint16_t* table = cu->insns + cu->current_dalvik_offset + table_offset;
uint16_t table_magic = *table;
if (table_magic == 0x100) {
cg->GenPackedSwitch(cu, table_offset, rl_src);
} else {
DCHECK_EQ(table_magic, 0x200);
cg->GenSparseSwitch(cu, table_offset, rl_src);
}
}
static void CvtInvoke(CompilationUnit* cu, llvm::CallInst* call_inst, bool is_void,
bool is_filled_new_array)
{
Codegen* cg = cu->cg.get();
CallInfo* info = static_cast<CallInfo*>(NewMem(cu, sizeof(CallInfo), true, kAllocMisc));
if (is_void) {
info->result.location = kLocInvalid;
} else {
info->result = GetLoc(cu, call_inst);
}
llvm::ConstantInt* invoke_type_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(0));
llvm::ConstantInt* method_index_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(1));
llvm::ConstantInt* opt_flags_val =
llvm::dyn_cast<llvm::ConstantInt>(call_inst->getArgOperand(2));
info->type = static_cast<InvokeType>(invoke_type_val->getZExtValue());
info->index = method_index_val->getZExtValue();
info->opt_flags = opt_flags_val->getZExtValue();
info->offset = cu->current_dalvik_offset;
// Count the argument words, and then build argument array.
info->num_arg_words = 0;
for (unsigned int i = 3; i < call_inst->getNumArgOperands(); i++) {
RegLocation t_loc = GetLoc(cu, call_inst->getArgOperand(i));
info->num_arg_words += t_loc.wide ? 2 : 1;
}
info->args = (info->num_arg_words == 0) ? NULL : static_cast<RegLocation*>
(NewMem(cu, sizeof(RegLocation) * info->num_arg_words, false, kAllocMisc));
// Now, fill in the location records, synthesizing high loc of wide vals
for (int i = 3, next = 0; next < info->num_arg_words;) {
info->args[next] = GetLoc(cu, call_inst->getArgOperand(i++));
if (info->args[next].wide) {
next++;
// TODO: Might make sense to mark this as an invalid loc
info->args[next].orig_sreg = info->args[next-1].orig_sreg+1;
info->args[next].s_reg_low = info->args[next-1].s_reg_low+1;
}
next++;
}
// TODO - rework such that we no longer need is_range
info->is_range = (info->num_arg_words > 5);
if (is_filled_new_array) {
cg->GenFilledNewArray(cu, info);
} else {
cg->GenInvoke(cu, info);
}
}
/* Look up the RegLocation associated with a Value. Must already be defined */
static RegLocation ValToLoc(CompilationUnit* cu, llvm::Value* val)
{
SafeMap<llvm::Value*, RegLocation>::iterator it = cu->loc_map.find(val);
DCHECK(it != cu->loc_map.end()) << "Missing definition";
return it->second;
}
static bool BitcodeBlockCodeGen(CompilationUnit* cu, llvm::BasicBlock* bb)
{
Codegen* cg = cu->cg.get();
while (cu->llvm_blocks.find(bb) == cu->llvm_blocks.end()) {
llvm::BasicBlock* next_bb = NULL;
cu->llvm_blocks.insert(bb);
bool is_entry = (bb == &cu->func->getEntryBlock());
// Define the starting label
LIR* block_label = cu->block_to_label_map.Get(bb);
// Extract the type and starting offset from the block's name
char block_type = kInvalidBlock;
if (is_entry) {
block_type = kNormalBlock;
block_label->operands[0] = 0;
} else if (!bb->hasName()) {
block_type = kNormalBlock;
block_label->operands[0] = DexFile::kDexNoIndex;
} else {
std::string block_name = bb->getName().str();
int dummy;
sscanf(block_name.c_str(), kLabelFormat, &block_type, &block_label->operands[0], &dummy);
cu->current_dalvik_offset = block_label->operands[0];
}
DCHECK((block_type == kNormalBlock) || (block_type == kCatchBlock));
cu->current_dalvik_offset = block_label->operands[0];
// Set the label kind
block_label->opcode = kPseudoNormalBlockLabel;
// Insert the label
AppendLIR(cu, block_label);
LIR* head_lir = NULL;
if (block_type == kCatchBlock) {
head_lir = NewLIR0(cu, kPseudoExportedPC);
}
// Free temp registers and reset redundant store tracking */
ResetRegPool(cu);
ResetDefTracking(cu);
//TODO: restore oat incoming liveness optimization
ClobberAllRegs(cu);
if (is_entry) {
RegLocation* ArgLocs = static_cast<RegLocation*>
(NewMem(cu, sizeof(RegLocation) * cu->num_ins, true, kAllocMisc));
llvm::Function::arg_iterator it(cu->func->arg_begin());
llvm::Function::arg_iterator it_end(cu->func->arg_end());
// Skip past Method*
it++;
for (unsigned i = 0; it != it_end; ++it) {
llvm::Value* val = it;
ArgLocs[i++] = ValToLoc(cu, val);
llvm::Type* ty = val->getType();
if ((ty == cu->irb->getInt64Ty()) || (ty == cu->irb->getDoubleTy())) {
ArgLocs[i] = ArgLocs[i-1];
ArgLocs[i].low_reg = ArgLocs[i].high_reg;
ArgLocs[i].orig_sreg++;
ArgLocs[i].s_reg_low = INVALID_SREG;
ArgLocs[i].high_word = true;
i++;
}
}
cg->GenEntrySequence(cu, ArgLocs, cu->method_loc);
}
// 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 next_it = ++it;
// Extract the Dalvik offset from the instruction
uint32_t opcode = inst->getOpcode();
llvm::MDNode* dex_offset_node = inst->getMetadata("DexOff");
if (dex_offset_node != NULL) {
llvm::ConstantInt* dex_offset_value =
static_cast<llvm::ConstantInt*>(dex_offset_node->getOperand(0));
cu->current_dalvik_offset = dex_offset_value->getZExtValue();
}
ResetRegPool(cu);
if (cu->disable_opt & (1 << kTrackLiveTemps)) {
ClobberAllRegs(cu);
}
if (cu->disable_opt & (1 << kSuppressLoads)) {
ResetDefTracking(cu);
}
#ifndef NDEBUG
/* Reset temp tracking sanity check */
cu->live_sreg = INVALID_SREG;
#endif
// TODO: use llvm opcode name here instead of "boundary" if verbose
LIR* boundary_lir = MarkBoundary(cu, cu->current_dalvik_offset, "boundary");
/* Remember the first LIR for thisl block*/
if (head_lir == NULL) {
head_lir = boundary_lir;
head_lir->def_mask = ENCODE_ALL;
}
switch(opcode) {
case llvm::Instruction::ICmp: {
llvm::Instruction* next_inst = next_it;
llvm::BranchInst* br_inst = llvm::dyn_cast<llvm::BranchInst>(next_inst);
if (br_inst != NULL /* and... */) {
CvtICmpBr(cu, inst, br_inst);
++it;
} else {
CvtICmp(cu, inst);
}
}
break;
case llvm::Instruction::Call: {
llvm::CallInst* call_inst = llvm::dyn_cast<llvm::CallInst>(inst);
llvm::Function* callee = call_inst->getCalledFunction();
greenland::IntrinsicHelper::IntrinsicId id =
cu->intrinsic_helper->GetIntrinsicId(callee);
switch (id) {
case greenland::IntrinsicHelper::AllocaShadowFrame:
case greenland::IntrinsicHelper::PopShadowFrame:
case greenland::IntrinsicHelper::SetVReg:
// Ignore shadow frame stuff for quick compiler
break;
case greenland::IntrinsicHelper::CopyInt:
case greenland::IntrinsicHelper::CopyObj:
case greenland::IntrinsicHelper::CopyFloat:
case greenland::IntrinsicHelper::CopyLong:
case greenland::IntrinsicHelper::CopyDouble:
CvtCopy(cu, call_inst);
break;
case greenland::IntrinsicHelper::ConstInt:
case greenland::IntrinsicHelper::ConstObj:
case greenland::IntrinsicHelper::ConstLong:
case greenland::IntrinsicHelper::ConstFloat:
case greenland::IntrinsicHelper::ConstDouble:
CvtConst(cu, call_inst);
break;
case greenland::IntrinsicHelper::DivInt:
case greenland::IntrinsicHelper::DivLong:
CvtBinOp(cu, kOpDiv, inst);
break;
case greenland::IntrinsicHelper::RemInt:
case greenland::IntrinsicHelper::RemLong:
CvtBinOp(cu, kOpRem, inst);
break;
case greenland::IntrinsicHelper::MethodInfo:
// Already dealt with - just ignore it here.
break;
case greenland::IntrinsicHelper::CheckSuspend:
cg->GenSuspendTest(cu, 0 /* opt_flags already applied */);
break;
case greenland::IntrinsicHelper::HLInvokeObj:
case greenland::IntrinsicHelper::HLInvokeFloat:
case greenland::IntrinsicHelper::HLInvokeDouble:
case greenland::IntrinsicHelper::HLInvokeLong:
case greenland::IntrinsicHelper::HLInvokeInt:
CvtInvoke(cu, call_inst, false /* is_void */, false /* new_array */);
break;
case greenland::IntrinsicHelper::HLInvokeVoid:
CvtInvoke(cu, call_inst, true /* is_void */, false /* new_array */);
break;
case greenland::IntrinsicHelper::HLFilledNewArray:
CvtInvoke(cu, call_inst, false /* is_void */, true /* new_array */);
break;
case greenland::IntrinsicHelper::HLFillArrayData:
CvtFillArrayData(cu, call_inst);
break;
case greenland::IntrinsicHelper::ConstString:
CvtConstObject(cu, call_inst, true /* is_string */);
break;
case greenland::IntrinsicHelper::ConstClass:
CvtConstObject(cu, call_inst, false /* is_string */);
break;
case greenland::IntrinsicHelper::HLCheckCast:
CvtCheckCast(cu, call_inst);
break;
case greenland::IntrinsicHelper::NewInstance:
CvtNewInstance(cu, call_inst);
break;
case greenland::IntrinsicHelper::HLSgetObject:
CvtSget(cu, call_inst, false /* wide */, true /* Object */);
break;
case greenland::IntrinsicHelper::HLSget:
case greenland::IntrinsicHelper::HLSgetFloat:
case greenland::IntrinsicHelper::HLSgetBoolean:
case greenland::IntrinsicHelper::HLSgetByte:
case greenland::IntrinsicHelper::HLSgetChar:
case greenland::IntrinsicHelper::HLSgetShort:
CvtSget(cu, call_inst, false /* wide */, false /* Object */);
break;
case greenland::IntrinsicHelper::HLSgetWide:
case greenland::IntrinsicHelper::HLSgetDouble:
CvtSget(cu, call_inst, true /* wide */, false /* Object */);
break;
case greenland::IntrinsicHelper::HLSput:
case greenland::IntrinsicHelper::HLSputFloat:
case greenland::IntrinsicHelper::HLSputBoolean:
case greenland::IntrinsicHelper::HLSputByte:
case greenland::IntrinsicHelper::HLSputChar:
case greenland::IntrinsicHelper::HLSputShort:
CvtSput(cu, call_inst, false /* wide */, false /* Object */);
break;
case greenland::IntrinsicHelper::HLSputWide:
case greenland::IntrinsicHelper::HLSputDouble:
CvtSput(cu, call_inst, true /* wide */, false /* Object */);
break;
case greenland::IntrinsicHelper::HLSputObject:
CvtSput(cu, call_inst, false /* wide */, true /* Object */);
break;
case greenland::IntrinsicHelper::GetException:
CvtMoveException(cu, call_inst);
break;
case greenland::IntrinsicHelper::HLThrowException:
CvtThrow(cu, call_inst);
break;
case greenland::IntrinsicHelper::MonitorEnter:
CvtMonitorEnterExit(cu, true /* is_enter */, call_inst);
break;
case greenland::IntrinsicHelper::MonitorExit:
CvtMonitorEnterExit(cu, false /* is_enter */, call_inst);
break;
case greenland::IntrinsicHelper::OptArrayLength:
CvtArrayLength(cu, call_inst);
break;
case greenland::IntrinsicHelper::NewArray:
CvtNewArray(cu, call_inst);
break;
case greenland::IntrinsicHelper::InstanceOf:
CvtInstanceOf(cu, call_inst);
break;
case greenland::IntrinsicHelper::HLArrayGet:
case greenland::IntrinsicHelper::HLArrayGetObject:
case greenland::IntrinsicHelper::HLArrayGetFloat:
CvtAget(cu, call_inst, kWord, 2);
break;
case greenland::IntrinsicHelper::HLArrayGetWide:
case greenland::IntrinsicHelper::HLArrayGetDouble:
CvtAget(cu, call_inst, kLong, 3);
break;
case greenland::IntrinsicHelper::HLArrayGetBoolean:
CvtAget(cu, call_inst, kUnsignedByte, 0);
break;
case greenland::IntrinsicHelper::HLArrayGetByte:
CvtAget(cu, call_inst, kSignedByte, 0);
break;
case greenland::IntrinsicHelper::HLArrayGetChar:
CvtAget(cu, call_inst, kUnsignedHalf, 1);
break;
case greenland::IntrinsicHelper::HLArrayGetShort:
CvtAget(cu, call_inst, kSignedHalf, 1);
break;
case greenland::IntrinsicHelper::HLArrayPut:
case greenland::IntrinsicHelper::HLArrayPutFloat:
CvtAputPrimitive(cu, call_inst, kWord, 2);
break;
case greenland::IntrinsicHelper::HLArrayPutObject:
CvtAputObj(cu, call_inst);
break;
case greenland::IntrinsicHelper::HLArrayPutWide:
case greenland::IntrinsicHelper::HLArrayPutDouble:
CvtAputPrimitive(cu, call_inst, kLong, 3);
break;
case greenland::IntrinsicHelper::HLArrayPutBoolean:
CvtAputPrimitive(cu, call_inst, kUnsignedByte, 0);
break;
case greenland::IntrinsicHelper::HLArrayPutByte:
CvtAputPrimitive(cu, call_inst, kSignedByte, 0);
break;
case greenland::IntrinsicHelper::HLArrayPutChar:
CvtAputPrimitive(cu, call_inst, kUnsignedHalf, 1);
break;
case greenland::IntrinsicHelper::HLArrayPutShort:
CvtAputPrimitive(cu, call_inst, kSignedHalf, 1);
break;
case greenland::IntrinsicHelper::HLIGet:
case greenland::IntrinsicHelper::HLIGetFloat:
CvtIget(cu, call_inst, kWord, false /* is_wide */, false /* obj */);
break;
case greenland::IntrinsicHelper::HLIGetObject:
CvtIget(cu, call_inst, kWord, false /* is_wide */, true /* obj */);
break;
case greenland::IntrinsicHelper::HLIGetWide:
case greenland::IntrinsicHelper::HLIGetDouble:
CvtIget(cu, call_inst, kLong, true /* is_wide */, false /* obj */);
break;
case greenland::IntrinsicHelper::HLIGetBoolean:
CvtIget(cu, call_inst, kUnsignedByte, false /* is_wide */,
false /* obj */);
break;
case greenland::IntrinsicHelper::HLIGetByte:
CvtIget(cu, call_inst, kSignedByte, false /* is_wide */,
false /* obj */);
break;
case greenland::IntrinsicHelper::HLIGetChar:
CvtIget(cu, call_inst, kUnsignedHalf, false /* is_wide */,
false /* obj */);
break;
case greenland::IntrinsicHelper::HLIGetShort:
CvtIget(cu, call_inst, kSignedHalf, false /* is_wide */,
false /* obj */);
break;
case greenland::IntrinsicHelper::HLIPut:
case greenland::IntrinsicHelper::HLIPutFloat:
CvtIput(cu, call_inst, kWord, false /* is_wide */, false /* obj */);
break;
case greenland::IntrinsicHelper::HLIPutObject:
CvtIput(cu, call_inst, kWord, false /* is_wide */, true /* obj */);
break;
case greenland::IntrinsicHelper::HLIPutWide:
case greenland::IntrinsicHelper::HLIPutDouble:
CvtIput(cu, call_inst, kLong, true /* is_wide */, false /* obj */);
break;
case greenland::IntrinsicHelper::HLIPutBoolean:
CvtIput(cu, call_inst, kUnsignedByte, false /* is_wide */,
false /* obj */);
break;
case greenland::IntrinsicHelper::HLIPutByte:
CvtIput(cu, call_inst, kSignedByte, false /* is_wide */,
false /* obj */);
break;
case greenland::IntrinsicHelper::HLIPutChar:
CvtIput(cu, call_inst, kUnsignedHalf, false /* is_wide */,
false /* obj */);
break;
case greenland::IntrinsicHelper::HLIPutShort:
CvtIput(cu, call_inst, kSignedHalf, false /* is_wide */,
false /* obj */);
break;
case greenland::IntrinsicHelper::IntToChar:
CvtIntNarrowing(cu, call_inst, Instruction::INT_TO_CHAR);
break;
case greenland::IntrinsicHelper::IntToShort:
CvtIntNarrowing(cu, call_inst, Instruction::INT_TO_SHORT);
break;
case greenland::IntrinsicHelper::IntToByte:
CvtIntNarrowing(cu, call_inst, Instruction::INT_TO_BYTE);
break;
case greenland::IntrinsicHelper::F2I:
case greenland::IntrinsicHelper::D2I:
case greenland::IntrinsicHelper::F2L:
case greenland::IntrinsicHelper::D2L:
CvtFPToInt(cu, call_inst);
break;
case greenland::IntrinsicHelper::CmplFloat:
CvtFPCompare(cu, call_inst, Instruction::CMPL_FLOAT);
break;
case greenland::IntrinsicHelper::CmpgFloat:
CvtFPCompare(cu, call_inst, Instruction::CMPG_FLOAT);
break;
case greenland::IntrinsicHelper::CmplDouble:
CvtFPCompare(cu, call_inst, Instruction::CMPL_DOUBLE);
break;
case greenland::IntrinsicHelper::CmpgDouble:
CvtFPCompare(cu, call_inst, Instruction::CMPG_DOUBLE);
break;
case greenland::IntrinsicHelper::CmpLong:
CvtLongCompare(cu, call_inst);
break;
case greenland::IntrinsicHelper::SHLLong:
CvtShiftOp(cu, Instruction::SHL_LONG, call_inst);
break;
case greenland::IntrinsicHelper::SHRLong:
CvtShiftOp(cu, Instruction::SHR_LONG, call_inst);
break;
case greenland::IntrinsicHelper::USHRLong:
CvtShiftOp(cu, Instruction::USHR_LONG, call_inst);
break;
case greenland::IntrinsicHelper::SHLInt:
CvtShiftOp(cu, Instruction::SHL_INT, call_inst);
break;
case greenland::IntrinsicHelper::SHRInt:
CvtShiftOp(cu, Instruction::SHR_INT, call_inst);
break;
case greenland::IntrinsicHelper::USHRInt:
CvtShiftOp(cu, Instruction::USHR_INT, call_inst);
break;
case greenland::IntrinsicHelper::CatchTargets: {
llvm::SwitchInst* sw_inst =
llvm::dyn_cast<llvm::SwitchInst>(next_it);
DCHECK(sw_inst != NULL);
/*
* Discard the edges and the following conditional branch.
* Do a direct branch to the default target (which is the
* "work" portion of the pair.
* TODO: awful code layout - rework
*/
llvm::BasicBlock* target_bb = sw_inst->getDefaultDest();
DCHECK(target_bb != NULL);
cg->OpUnconditionalBranch(cu, cu->block_to_label_map.Get(target_bb));
++it;
// Set next bb to default target - improves code layout
next_bb = target_bb;
}
break;
default:
LOG(FATAL) << "Unexpected intrinsic " << cu->intrinsic_helper->GetName(id);
}
}
break;
case llvm::Instruction::Br: CvtBr(cu, inst); break;
case llvm::Instruction::Add: CvtBinOp(cu, kOpAdd, inst); break;
case llvm::Instruction::Sub: CvtBinOp(cu, kOpSub, inst); break;
case llvm::Instruction::Mul: CvtBinOp(cu, kOpMul, inst); break;
case llvm::Instruction::SDiv: CvtBinOp(cu, kOpDiv, inst); break;
case llvm::Instruction::SRem: CvtBinOp(cu, kOpRem, inst); break;
case llvm::Instruction::And: CvtBinOp(cu, kOpAnd, inst); break;
case llvm::Instruction::Or: CvtBinOp(cu, kOpOr, inst); break;
case llvm::Instruction::Xor: CvtBinOp(cu, kOpXor, inst); break;
case llvm::Instruction::PHI: CvtPhi(cu, inst); break;
case llvm::Instruction::Ret: CvtRet(cu, inst); break;
case llvm::Instruction::FAdd: CvtBinFPOp(cu, kOpAdd, inst); break;
case llvm::Instruction::FSub: CvtBinFPOp(cu, kOpSub, inst); break;
case llvm::Instruction::FMul: CvtBinFPOp(cu, kOpMul, inst); break;
case llvm::Instruction::FDiv: CvtBinFPOp(cu, kOpDiv, inst); break;
case llvm::Instruction::FRem: CvtBinFPOp(cu, kOpRem, inst); break;
case llvm::Instruction::SIToFP: CvtIntToFP(cu, inst); break;
case llvm::Instruction::FPTrunc: CvtDoubleToFloat(cu, inst); break;
case llvm::Instruction::FPExt: CvtFloatToDouble(cu, inst); break;
case llvm::Instruction::Trunc: CvtTrunc(cu, inst); break;
case llvm::Instruction::ZExt: CvtIntExt(cu, inst, false /* signed */);
break;
case llvm::Instruction::SExt: CvtIntExt(cu, inst, true /* signed */);
break;
case llvm::Instruction::Switch: CvtSwitch(cu, inst); break;
case llvm::Instruction::Unreachable:
break; // FIXME: can we really ignore these?
case llvm::Instruction::Shl:
case llvm::Instruction::LShr:
case llvm::Instruction::AShr:
case llvm::Instruction::Invoke:
case llvm::Instruction::FPToUI:
case llvm::Instruction::FPToSI:
case llvm::Instruction::UIToFP:
case llvm::Instruction::PtrToInt:
case llvm::Instruction::IntToPtr:
case llvm::Instruction::FCmp:
case llvm::Instruction::URem:
case llvm::Instruction::UDiv:
case llvm::Instruction::Resume:
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: " << inst->getOpcodeName();
break;
}
}
if (head_lir != NULL) {
ApplyLocalOptimizations(cu, head_lir, cu->last_lir_insn);
}
if (next_bb != NULL) {
bb = next_bb;
next_bb = NULL;
}
}
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 ssa_rep 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 MethodBitcode2LIR(CompilationUnit* cu)
{
Codegen* cg = cu->cg.get();
llvm::Function* func = cu->func;
int num_basic_blocks = func->getBasicBlockList().size();
// Allocate a list for LIR basic block labels
cu->block_label_list =
static_cast<LIR*>(NewMem(cu, sizeof(LIR) * num_basic_blocks, true, kAllocLIR));
LIR* label_list = cu->block_label_list;
int next_label = 0;
for (llvm::Function::iterator i = func->begin(), e = func->end(); i != e; ++i) {
cu->block_to_label_map.Put(static_cast<llvm::BasicBlock*>(i),
&label_list[next_label++]);
}
/*
* Keep honest - clear reg_locations, Value => RegLocation,
* promotion map and VmapTables.
*/
cu->loc_map.clear(); // Start fresh
cu->reg_location = NULL;
for (int i = 0; i < cu->num_dalvik_registers + cu->num_compiler_temps + 1; i++) {
cu->promotion_map[i].core_location = kLocDalvikFrame;
cu->promotion_map[i].fp_location = kLocDalvikFrame;
}
cu->core_spill_mask = 0;
cu->num_core_spills = 0;
cu->fp_spill_mask = 0;
cu->num_fp_spills = 0;
cu->core_vmap_table.clear();
cu->fp_vmap_table.clear();
/*
* At this point, we've lost all knowledge of register promotion.
* Rebuild that info from the MethodInfo intrinsic (if it
* exists - not required for correctness). Normally, this will
* be the first instruction we encounter, so we won't have to iterate
* through everything.
*/
for (llvm::inst_iterator i = llvm::inst_begin(func), e = llvm::inst_end(func); i != e; ++i) {
llvm::CallInst* call_inst = llvm::dyn_cast<llvm::CallInst>(&*i);
if (call_inst != NULL) {
llvm::Function* callee = call_inst->getCalledFunction();
greenland::IntrinsicHelper::IntrinsicId id =
cu->intrinsic_helper->GetIntrinsicId(callee);
if (id == greenland::IntrinsicHelper::MethodInfo) {
if (cu->verbose) {
LOG(INFO) << "Found MethodInfo";
}
llvm::MDNode* reg_info_node = call_inst->getMetadata("RegInfo");
if (reg_info_node != NULL) {
llvm::ConstantInt* num_ins_value =
static_cast<llvm::ConstantInt*>(reg_info_node->getOperand(0));
llvm::ConstantInt* num_regs_value =
static_cast<llvm::ConstantInt*>(reg_info_node->getOperand(1));
llvm::ConstantInt* num_outs_value =
static_cast<llvm::ConstantInt*>(reg_info_node->getOperand(2));
llvm::ConstantInt* num_compiler_temps_value =
static_cast<llvm::ConstantInt*>(reg_info_node->getOperand(3));
llvm::ConstantInt* num_ssa_regs_value =
static_cast<llvm::ConstantInt*>(reg_info_node->getOperand(4));
if (cu->verbose) {
LOG(INFO) << "RegInfo - Ins:" << num_ins_value->getZExtValue()
<< ", Regs:" << num_regs_value->getZExtValue()
<< ", Outs:" << num_outs_value->getZExtValue()
<< ", CTemps:" << num_compiler_temps_value->getZExtValue()
<< ", SSARegs:" << num_ssa_regs_value->getZExtValue();
}
}
llvm::MDNode* pmap_info_node = call_inst->getMetadata("PromotionMap");
if (pmap_info_node != NULL) {
int elems = pmap_info_node->getNumOperands();
if (cu->verbose) {
LOG(INFO) << "PMap size: " << elems;
}
for (int i = 0; i < elems; i++) {
llvm::ConstantInt* raw_map_data =
static_cast<llvm::ConstantInt*>(pmap_info_node->getOperand(i));
uint32_t map_data = raw_map_data->getZExtValue();
PromotionMap* p = &cu->promotion_map[i];
p->first_in_pair = (map_data >> 24) & 0xff;
p->FpReg = (map_data >> 16) & 0xff;
p->core_reg = (map_data >> 8) & 0xff;
p->fp_location = static_cast<RegLocationType>((map_data >> 4) & 0xf);
if (p->fp_location == kLocPhysReg) {
RecordFpPromotion(cu, p->FpReg, i);
}
p->core_location = static_cast<RegLocationType>(map_data & 0xf);
if (p->core_location == kLocPhysReg) {
RecordCorePromotion(cu, p->core_reg, i);
}
}
if (cu->verbose) {
DumpPromotionMap(cu);
}
}
break;
}
}
}
cg->AdjustSpillMask(cu);
cu->frame_size = ComputeFrameSize(cu);
// Create RegLocations for arguments
llvm::Function::arg_iterator it(cu->func->arg_begin());
llvm::Function::arg_iterator it_end(cu->func->arg_end());
for (; it != it_end; ++it) {
llvm::Value* val = it;
CreateLocFromValue(cu, val);
}
// Create RegLocations for all non-argument defintions
for (llvm::inst_iterator i = llvm::inst_begin(func), e = llvm::inst_end(func); i != e; ++i) {
llvm::Value* val = &*i;
if (val->hasName() && (val->getName().str().c_str()[0] == 'v')) {
CreateLocFromValue(cu, val);
}
}
// Walk the blocks, generating code.
for (llvm::Function::iterator i = cu->func->begin(), e = cu->func->end(); i != e; ++i) {
BitcodeBlockCodeGen(cu, static_cast<llvm::BasicBlock*>(i));
}
cg->HandleSuspendLaunchPads(cu);
cg->HandleThrowLaunchPads(cu);
cg->HandleIntrinsicLaunchPads(cu);
cu->func->eraseFromParent();
cu->func = NULL;
}
} // namespace art