Move some helper functions to gbc_expander.
Introduce ScopedExpandToBasicBlock.
Implement IGet/IPut.
Change-Id: I73d33282b68acac7cae67912d194b2638e6e92a4
diff --git a/src/compiler_llvm/gbc_expander.cc b/src/compiler_llvm/gbc_expander.cc
index fa8bcea..a0693a8 100644
--- a/src/compiler_llvm/gbc_expander.cc
+++ b/src/compiler_llvm/gbc_expander.cc
@@ -17,9 +17,12 @@
#include "ir_builder.h"
#include "utils_llvm.h"
+#include "compiler.h"
#include "greenland/intrinsic_helper.h"
+#include "oat_compilation_unit.h"
#include "object.h"
#include "thread.h"
+#include "verifier/method_verifier.h"
#include <llvm/ADT/STLExtras.h>
#include <llvm/Intrinsics.h>
@@ -50,6 +53,25 @@
uint32_t shadow_frame_size_;
private:
+ // TODO: Init these fields
+ Compiler* compiler_;
+
+ const DexFile* dex_file_;
+ DexCache* dex_cache_;
+ const DexFile::CodeItem* code_item_;
+
+ OatCompilationUnit* oat_compilation_unit_;
+
+ uint32_t method_idx_;
+
+ llvm::Function* func_;
+
+ std::vector<llvm::BasicBlock*> basic_blocks_;
+
+ std::vector<llvm::BasicBlock*> basic_block_landing_pads_;
+ llvm::BasicBlock* basic_block_unwind_;
+
+ private:
//----------------------------------------------------------------------------
// Constant for GBC expansion
//----------------------------------------------------------------------------
@@ -64,17 +86,17 @@
// Helper function for GBC expansion
//----------------------------------------------------------------------------
- // Split the basic block containing INST at INST and insert a sequence of
- // basic blocks with a single entry at BEGIN_BB and a single exit at END_BB
- // before INST.
- llvm::BasicBlock*
- SplitAndInsertBasicBlocksAfter(llvm::BasicBlock::iterator inst,
- llvm::BasicBlock* begin_bb,
- llvm::BasicBlock* end_bb);
-
llvm::Value* ExpandToRuntime(runtime_support::RuntimeId rt,
llvm::CallInst& inst);
+ uint64_t LV2UInt(llvm::Value* lv) {
+ return llvm::cast<llvm::ConstantInt>(lv)->getZExtValue();
+ }
+
+ int64_t LV2SInt(llvm::Value* lv) {
+ return llvm::cast<llvm::ConstantInt>(lv)->getSExtValue();
+ }
+
private:
// TODO: Almost all Emit* are directly copy-n-paste from MethodCompiler.
// Refactor these utility functions from MethodCompiler to avoid forking.
@@ -198,6 +220,75 @@
llvm::Value* EmitCompareResultSelection(llvm::Value* cmp_eq,
llvm::Value* cmp_lt);
+ class ScopedExpandToBasicBlock {
+ public:
+ ScopedExpandToBasicBlock(IRBuilder& irb, llvm::Instruction* expand_inst)
+ : irb_(irb), expand_inst_(expand_inst) {
+ llvm::Function* func = expand_inst_->getParent()->getParent();
+ begin_bb_ = llvm::BasicBlock::Create(irb_.getContext(),
+ "",
+ func);
+ irb_.SetInsertPoint(begin_bb_);
+ }
+
+ ~ScopedExpandToBasicBlock() {
+ llvm::BasicBlock* end_bb = irb_.GetInsertBlock();
+ SplitAndInsertBasicBlocksAfter(*expand_inst_, begin_bb_, end_bb);
+ }
+
+ private:
+ // Split the basic block containing INST at INST and insert a sequence of
+ // basic blocks with a single entry at BEGIN_BB and a single exit at END_BB
+ // before INST.
+ llvm::BasicBlock*
+ SplitAndInsertBasicBlocksAfter(llvm::BasicBlock::iterator inst,
+ llvm::BasicBlock* begin_bb,
+ llvm::BasicBlock* end_bb);
+ private:
+ IRBuilder& irb_;
+ llvm::Instruction* expand_inst_;
+ llvm::BasicBlock* begin_bb_;
+ };
+
+ llvm::Value* Expand_HLIGet(llvm::CallInst& call_inst, JType field_jty);
+ void Expand_HLIPut(llvm::CallInst& call_inst, JType field_jty);
+
+ void EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr);
+
+ void EmitUpdateDexPC(uint32_t dex_pc);
+
+ void EmitGuard_DivZeroException(uint32_t dex_pc,
+ llvm::Value* denominator,
+ JType op_jty);
+
+ void EmitGuard_NullPointerException(uint32_t dex_pc,
+ llvm::Value* object);
+
+ void EmitGuard_ArrayIndexOutOfBoundsException(uint32_t dex_pc,
+ llvm::Value* array,
+ llvm::Value* index);
+
+ void EmitGuard_ArrayException(uint32_t dex_pc,
+ llvm::Value* array,
+ llvm::Value* index);
+
+ llvm::FunctionType* GetFunctionType(uint32_t method_idx, bool is_static);
+
+ llvm::BasicBlock* GetBasicBlock(uint32_t dex_pc);
+
+ llvm::BasicBlock* CreateBasicBlockWithDexPC(uint32_t dex_pc,
+ const char* postfix);
+
+ int32_t GetTryItemOffset(uint32_t dex_pc);
+
+ llvm::BasicBlock* GetLandingPadBasicBlock(uint32_t dex_pc);
+
+ llvm::BasicBlock* GetUnwindBasicBlock();
+
+ void EmitGuard_ExceptionLandingPad(uint32_t dex_pc);
+
+ void EmitBranchExceptionLandingPad(uint32_t dex_pc);
+
//----------------------------------------------------------------------------
// Expand Arithmetic Helper Intrinsics
//----------------------------------------------------------------------------
@@ -264,6 +355,7 @@
shadow_frame_ = NULL;
old_shadow_frame_ = NULL;
shadow_frame_size_ = 0;
+ func_ = &func;
// Remove the instruction containing in the work_list
while (!work_list.empty()) {
@@ -294,9 +386,10 @@
}
llvm::BasicBlock*
-GBCExpanderPass::SplitAndInsertBasicBlocksAfter(llvm::BasicBlock::iterator inst,
- llvm::BasicBlock* begin_bb,
- llvm::BasicBlock* end_bb) {
+GBCExpanderPass::ScopedExpandToBasicBlock::
+SplitAndInsertBasicBlocksAfter(llvm::BasicBlock::iterator inst,
+ llvm::BasicBlock* begin_bb,
+ llvm::BasicBlock* end_bb) {
llvm::BasicBlock* original = inst->getParent();
llvm::Function* parent = original->getParent();
@@ -304,7 +397,7 @@
llvm::BasicBlock *insert_before =
llvm::next(llvm::Function::iterator(original)).getNodePtrUnchecked();
llvm::BasicBlock* a =
- llvm::BasicBlock::Create(context_, "", parent, insert_before);
+ llvm::BasicBlock::Create(irb_.getContext(), "", parent, insert_before);
// 2. Move all instructions in ORIGINAL after INST (included) to A
a->getInstList().splice(a->end(), original->getInstList(),
@@ -355,14 +448,11 @@
bool
GBCExpanderPass::EmitStackOverflowCheck(llvm::Instruction* first_non_alloca) {
+ ScopedExpandToBasicBlock eb(irb_, first_non_alloca);
+
llvm::Function* func = first_non_alloca->getParent()->getParent();
llvm::Module* module = func->getParent();
- llvm::BasicBlock* block_entry =
- llvm::BasicBlock::Create(context_, "stack_overflow_entry", func);
-
- irb_.SetInsertPoint(block_entry);
-
// Call llvm intrinsic function to get frame address.
llvm::Function* frameaddress =
llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::frameaddress);
@@ -406,9 +496,6 @@
}
irb_.SetInsertPoint(block_continue);
-
- SplitAndInsertBasicBlocksAfter(*first_non_alloca, block_entry, block_continue);
-
return true;
}
@@ -535,31 +622,14 @@
}
void GBCExpanderPass::Expand_TestSuspend(llvm::CallInst& call_inst) {
- llvm::Function* parent_func = irb_.GetInsertBlock()->getParent();
- llvm::BasicBlock* suspend_test_begin_bb =
- llvm::BasicBlock::Create(context_, "suspend_test", parent_func);
-
- irb_.SetInsertPoint(suspend_test_begin_bb);
+ ScopedExpandToBasicBlock eb(irb_, &call_inst);
irb_.Runtime().EmitTestSuspend();
-
- llvm::BasicBlock* suspend_test_end_bb = irb_.GetInsertBlock();
-
- SplitAndInsertBasicBlocksAfter(call_inst, suspend_test_begin_bb,
- suspend_test_end_bb);
return;
}
void GBCExpanderPass::Expand_MarkGCCard(llvm::CallInst& call_inst) {
- llvm::Function* parent_func = irb_.GetInsertBlock()->getParent();
- llvm::BasicBlock* begin_bb =
- llvm::BasicBlock::Create(context_, "mark_gc_card", parent_func);
-
- irb_.SetInsertPoint(begin_bb);
+ ScopedExpandToBasicBlock eb(irb_, &call_inst);
irb_.Runtime().EmitMarkGCCard(call_inst.getArgOperand(0), call_inst.getArgOperand(1));
-
- llvm::BasicBlock* end_bb = irb_.GetInsertBlock();
-
- SplitAndInsertBasicBlocksAfter(call_inst, begin_bb, end_bb);
return;
}
@@ -600,38 +670,14 @@
}
void GBCExpanderPass::Expand_LockObject(llvm::Value* obj) {
- llvm::BasicBlock::iterator lock_obj_inst = irb_.GetInsertPoint();
- llvm::Function* parent = irb_.GetInsertBlock()->getParent();
-
- llvm::BasicBlock* lock_obj_begin_bb =
- llvm::BasicBlock::Create(context_, "", parent);
-
- irb_.SetInsertPoint(lock_obj_begin_bb);
+ ScopedExpandToBasicBlock eb(irb_, irb_.GetInsertPoint());
rtb_.EmitLockObject(obj);
-
- llvm::BasicBlock* lock_obj_end_bb = irb_.GetInsertBlock();
-
- SplitAndInsertBasicBlocksAfter(lock_obj_inst, lock_obj_begin_bb,
- lock_obj_end_bb);
-
return;
}
void GBCExpanderPass::Expand_UnlockObject(llvm::Value* obj) {
- llvm::BasicBlock::iterator unlock_obj_inst = irb_.GetInsertPoint();
- llvm::Function* parent = irb_.GetInsertBlock()->getParent();
-
- llvm::BasicBlock* unlock_obj_begin_bb =
- llvm::BasicBlock::Create(context_, "", parent);
-
- irb_.SetInsertPoint(unlock_obj_begin_bb);
+ ScopedExpandToBasicBlock eb(irb_, irb_.GetInsertPoint());
rtb_.EmitUnlockObject(obj);
-
- llvm::BasicBlock* unlock_obj_end_bb = irb_.GetInsertBlock();
-
- SplitAndInsertBasicBlocksAfter(unlock_obj_inst, unlock_obj_begin_bb,
- unlock_obj_end_bb);
-
return;
}
@@ -872,17 +918,14 @@
llvm::Value* zero = irb_.getJZero(op_jty);
llvm::Value* neg_one = llvm::ConstantInt::getSigned(op_type, -1);
- llvm::BasicBlock::iterator div_rem_inst = irb_.GetInsertPoint();
- llvm::Function* parent = irb_.GetInsertBlock()->getParent();
+ ScopedExpandToBasicBlock eb(irb_, irb_.GetInsertPoint());
- llvm::BasicBlock* begin_div_rem =
- llvm::BasicBlock::Create(context_, "", parent);
+ llvm::Function* parent = irb_.GetInsertBlock()->getParent();
llvm::BasicBlock* eq_neg_one = llvm::BasicBlock::Create(context_, "", parent);
llvm::BasicBlock* ne_neg_one = llvm::BasicBlock::Create(context_, "", parent);
llvm::BasicBlock* neg_one_cont =
llvm::BasicBlock::Create(context_, "", parent);
- irb_.SetInsertPoint(begin_div_rem);
llvm::Value* is_equal_neg_one = irb_.CreateICmpEQ(divisor, neg_one);
irb_.CreateCondBr(is_equal_neg_one, eq_neg_one, ne_neg_one, kUnlikely);
@@ -920,8 +963,6 @@
result->addIncoming(eq_result, eq_neg_one);
result->addIncoming(ne_result, ne_neg_one);
- SplitAndInsertBasicBlocksAfter(div_rem_inst, begin_div_rem, neg_one_cont);
-
return result;
}
@@ -1009,6 +1050,8 @@
return EmitStackOverflowCheck(&*first_non_alloca);
}
+// ==== High-level intrinsic expander ==========================================
+
llvm::Value* GBCExpanderPass::Expand_FPCompare(llvm::Value* src1_value,
llvm::Value* src2_value,
bool gt_bias) {
@@ -1075,6 +1118,409 @@
}
}
+llvm::Value* GBCExpanderPass::Expand_HLIGet(llvm::CallInst& call_inst,
+ JType field_jty) {
+ ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+ uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+ llvm::Value* object_addr = call_inst.getArgOperand(1);
+ uint32_t field_idx = LV2UInt(call_inst.getArgOperand(2));
+
+ // TODO: opt_flags
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+
+ llvm::Value* field_value;
+
+ int field_offset;
+ bool is_volatile;
+ bool is_fast_path = compiler_->ComputeInstanceFieldInfo(
+ field_idx, oat_compilation_unit_, field_offset, is_volatile, false);
+
+ if (!is_fast_path) {
+ llvm::Function* runtime_func;
+
+ if (field_jty == kObject) {
+ runtime_func = irb_.GetRuntime(runtime_support::GetObjectInstance);
+ } else if (field_jty == kLong || field_jty == kDouble) {
+ runtime_func = irb_.GetRuntime(runtime_support::Get64Instance);
+ } else {
+ runtime_func = irb_.GetRuntime(runtime_support::Get32Instance);
+ }
+
+ llvm::ConstantInt* field_idx_value = irb_.getInt32(field_idx);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ EmitUpdateDexPC(dex_pc);
+
+ field_value = irb_.CreateCall3(runtime_func, field_idx_value,
+ method_object_addr, object_addr);
+
+ EmitGuard_ExceptionLandingPad(dex_pc);
+
+ } else {
+ DCHECK_GE(field_offset, 0);
+
+ llvm::PointerType* field_type =
+ irb_.getJType(field_jty, kField)->getPointerTo();
+
+ llvm::ConstantInt* field_offset_value = irb_.getPtrEquivInt(field_offset);
+
+ llvm::Value* field_addr =
+ irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
+
+ // TODO: Check is_volatile. We need to generate atomic load instruction
+ // when is_volatile is true.
+ field_value = irb_.CreateLoad(field_addr, kTBAAHeapInstance, field_jty);
+ }
+
+ if (field_jty == kFloat || field_jty == kDouble) {
+ field_value = irb_.CreateBitCast(field_value, irb_.getJType(field_jty, kReg));
+ }
+
+ return field_value;
+}
+
+void GBCExpanderPass::Expand_HLIPut(llvm::CallInst& call_inst,
+ JType field_jty) {
+ ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+ uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+ llvm::Value* object_addr = call_inst.getArgOperand(1);
+ llvm::Value* new_value = call_inst.getArgOperand(2);
+ uint32_t field_idx = LV2UInt(call_inst.getArgOperand(3));
+
+ if (field_jty == kFloat || field_jty == kDouble) {
+ new_value = irb_.CreateBitCast(new_value, irb_.getJType(field_jty, kReg));
+ }
+
+ // TODO: opt_flags
+ EmitGuard_NullPointerException(dex_pc, object_addr);
+
+ int field_offset;
+ bool is_volatile;
+ bool is_fast_path = compiler_->ComputeInstanceFieldInfo(
+ field_idx, oat_compilation_unit_, field_offset, is_volatile, true);
+
+ if (!is_fast_path) {
+ llvm::Function* runtime_func;
+
+ if (field_jty == kObject) {
+ runtime_func = irb_.GetRuntime(runtime_support::SetObjectInstance);
+ } else if (field_jty == kLong || field_jty == kDouble) {
+ runtime_func = irb_.GetRuntime(runtime_support::Set64Instance);
+ } else {
+ runtime_func = irb_.GetRuntime(runtime_support::Set32Instance);
+ }
+
+ llvm::Value* field_idx_value = irb_.getInt32(field_idx);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ EmitUpdateDexPC(dex_pc);
+
+ irb_.CreateCall4(runtime_func, field_idx_value,
+ method_object_addr, object_addr, new_value);
+
+ EmitGuard_ExceptionLandingPad(dex_pc);
+
+ } else {
+ DCHECK_GE(field_offset, 0);
+
+ llvm::PointerType* field_type =
+ irb_.getJType(field_jty, kField)->getPointerTo();
+
+ llvm::Value* field_offset_value = irb_.getPtrEquivInt(field_offset);
+
+ llvm::Value* field_addr =
+ irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
+
+ // TODO: Check is_volatile. We need to generate atomic store instruction
+ // when is_volatile is true.
+ irb_.CreateStore(new_value, field_addr, kTBAAHeapInstance, field_jty);
+
+ if (field_jty == kObject) { // If put an object, mark the GC card table.
+ EmitMarkGCCard(new_value, object_addr);
+ }
+ }
+
+ return;
+}
+
+void GBCExpanderPass::EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr) {
+ // Using runtime support, let the target can override by InlineAssembly.
+ irb_.Runtime().EmitMarkGCCard(value, target_addr);
+}
+
+void GBCExpanderPass::EmitUpdateDexPC(uint32_t dex_pc) {
+ irb_.StoreToObjectOffset(shadow_frame_,
+ ShadowFrame::DexPCOffset(),
+ irb_.getInt32(dex_pc),
+ kTBAAShadowFrame);
+}
+
+void GBCExpanderPass::EmitGuard_DivZeroException(uint32_t dex_pc,
+ llvm::Value* denominator,
+ JType op_jty) {
+ DCHECK(op_jty == kInt || op_jty == kLong) << op_jty;
+
+ llvm::Constant* zero = irb_.getJZero(op_jty);
+
+ llvm::Value* equal_zero = irb_.CreateICmpEQ(denominator, zero);
+
+ llvm::BasicBlock* block_exception = CreateBasicBlockWithDexPC(dex_pc, "div0");
+
+ llvm::BasicBlock* block_continue = CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+ irb_.CreateCondBr(equal_zero, block_exception, block_continue, kUnlikely);
+
+ irb_.SetInsertPoint(block_exception);
+ EmitUpdateDexPC(dex_pc);
+ irb_.CreateCall(irb_.GetRuntime(runtime_support::ThrowDivZeroException));
+ EmitBranchExceptionLandingPad(dex_pc);
+
+ irb_.SetInsertPoint(block_continue);
+}
+
+void GBCExpanderPass::EmitGuard_NullPointerException(uint32_t dex_pc,
+ llvm::Value* object) {
+ llvm::Value* equal_null = irb_.CreateICmpEQ(object, irb_.getJNull());
+
+ llvm::BasicBlock* block_exception =
+ CreateBasicBlockWithDexPC(dex_pc, "nullp");
+
+ llvm::BasicBlock* block_continue =
+ CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+ irb_.CreateCondBr(equal_null, block_exception, block_continue, kUnlikely);
+
+ irb_.SetInsertPoint(block_exception);
+ EmitUpdateDexPC(dex_pc);
+ irb_.CreateCall(irb_.GetRuntime(runtime_support::ThrowNullPointerException),
+ irb_.getInt32(dex_pc));
+ EmitBranchExceptionLandingPad(dex_pc);
+
+ irb_.SetInsertPoint(block_continue);
+}
+
+void
+GBCExpanderPass::EmitGuard_ArrayIndexOutOfBoundsException(uint32_t dex_pc,
+ llvm::Value* array,
+ llvm::Value* index) {
+ llvm::Value* array_len = EmitLoadArrayLength(array);
+
+ llvm::Value* cmp = irb_.CreateICmpUGE(index, array_len);
+
+ llvm::BasicBlock* block_exception =
+ CreateBasicBlockWithDexPC(dex_pc, "overflow");
+
+ llvm::BasicBlock* block_continue =
+ CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+ irb_.CreateCondBr(cmp, block_exception, block_continue, kUnlikely);
+
+ irb_.SetInsertPoint(block_exception);
+
+ EmitUpdateDexPC(dex_pc);
+ irb_.CreateCall2(irb_.GetRuntime(runtime_support::ThrowIndexOutOfBounds), index, array_len);
+ EmitBranchExceptionLandingPad(dex_pc);
+
+ irb_.SetInsertPoint(block_continue);
+}
+
+void GBCExpanderPass::EmitGuard_ArrayException(uint32_t dex_pc,
+ llvm::Value* array,
+ llvm::Value* index) {
+ EmitGuard_NullPointerException(dex_pc, array);
+ EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array, index);
+}
+
+llvm::FunctionType* GBCExpanderPass::GetFunctionType(uint32_t method_idx,
+ bool is_static) {
+ // Get method signature
+ DexFile::MethodId const& method_id = dex_file_->GetMethodId(method_idx);
+
+ uint32_t shorty_size;
+ const char* shorty = dex_file_->GetMethodShorty(method_id, &shorty_size);
+ CHECK_GE(shorty_size, 1u);
+
+ // Get return type
+ llvm::Type* ret_type = irb_.getJType(shorty[0], kAccurate);
+
+ // Get argument type
+ std::vector<llvm::Type*> args_type;
+
+ args_type.push_back(irb_.getJObjectTy()); // method object pointer
+
+ if (!is_static) {
+ args_type.push_back(irb_.getJType('L', kAccurate)); // "this" object pointer
+ }
+
+ for (uint32_t i = 1; i < shorty_size; ++i) {
+ args_type.push_back(irb_.getJType(shorty[i], kAccurate));
+ }
+
+ return llvm::FunctionType::get(ret_type, args_type, false);
+}
+
+
+llvm::BasicBlock* GBCExpanderPass::
+CreateBasicBlockWithDexPC(uint32_t dex_pc, const char* postfix) {
+ std::string name;
+
+#if !defined(NDEBUG)
+ StringAppendF(&name, "B%04x.%s", dex_pc, postfix);
+#endif
+
+ return llvm::BasicBlock::Create(context_, name, func_);
+}
+
+llvm::BasicBlock* GBCExpanderPass::GetBasicBlock(uint32_t dex_pc) {
+ DCHECK(dex_pc < code_item_->insns_size_in_code_units_);
+
+ return basic_blocks_[dex_pc];
+}
+
+int32_t GBCExpanderPass::GetTryItemOffset(uint32_t dex_pc) {
+ int32_t min = 0;
+ int32_t max = code_item_->tries_size_ - 1;
+
+ while (min <= max) {
+ int32_t mid = min + (max - min) / 2;
+
+ const DexFile::TryItem* ti = DexFile::GetTryItems(*code_item_, mid);
+ uint32_t start = ti->start_addr_;
+ uint32_t end = start + ti->insn_count_;
+
+ if (dex_pc < start) {
+ max = mid - 1;
+ } else if (dex_pc >= end) {
+ min = mid + 1;
+ } else {
+ return mid; // found
+ }
+ }
+
+ return -1; // not found
+}
+
+llvm::BasicBlock* GBCExpanderPass::GetLandingPadBasicBlock(uint32_t dex_pc) {
+ // Find the try item for this address in this method
+ int32_t ti_offset = GetTryItemOffset(dex_pc);
+
+ if (ti_offset == -1) {
+ return NULL; // No landing pad is available for this address.
+ }
+
+ // Check for the existing landing pad basic block
+ DCHECK_GT(basic_block_landing_pads_.size(), static_cast<size_t>(ti_offset));
+ llvm::BasicBlock* block_lpad = basic_block_landing_pads_[ti_offset];
+
+ if (block_lpad) {
+ // We have generated landing pad for this try item already. Return the
+ // same basic block.
+ return block_lpad;
+ }
+
+ // Get try item from code item
+ const DexFile::TryItem* ti = DexFile::GetTryItems(*code_item_, ti_offset);
+
+ std::string lpadname;
+
+#if !defined(NDEBUG)
+ StringAppendF(&lpadname, "lpad%d_%04x_to_%04x", ti_offset, ti->start_addr_, ti->handler_off_);
+#endif
+
+ // Create landing pad basic block
+ block_lpad = llvm::BasicBlock::Create(context_, lpadname, func_);
+
+ // Change IRBuilder insert point
+ llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+ irb_.SetInsertPoint(block_lpad);
+
+ // Find catch block with matching type
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ llvm::Value* ti_offset_value = irb_.getInt32(ti_offset);
+
+ llvm::Value* catch_handler_index_value =
+ irb_.CreateCall2(irb_.GetRuntime(runtime_support::FindCatchBlock),
+ method_object_addr, ti_offset_value);
+
+ // Switch instruction (Go to unwind basic block by default)
+ llvm::SwitchInst* sw =
+ irb_.CreateSwitch(catch_handler_index_value, GetUnwindBasicBlock());
+
+ // Cases with matched catch block
+ CatchHandlerIterator iter(*code_item_, ti->start_addr_);
+
+ for (uint32_t c = 0; iter.HasNext(); iter.Next(), ++c) {
+ sw->addCase(irb_.getInt32(c), GetBasicBlock(iter.GetHandlerAddress()));
+ }
+
+ // Restore the orignal insert point for IRBuilder
+ irb_.restoreIP(irb_ip_original);
+
+ // Cache this landing pad
+ DCHECK_GT(basic_block_landing_pads_.size(), static_cast<size_t>(ti_offset));
+ basic_block_landing_pads_[ti_offset] = block_lpad;
+
+ return block_lpad;
+}
+
+llvm::BasicBlock* GBCExpanderPass::GetUnwindBasicBlock() {
+ // Check the existing unwinding baisc block block
+ if (basic_block_unwind_ != NULL) {
+ return basic_block_unwind_;
+ }
+
+ // Create new basic block for unwinding
+ basic_block_unwind_ =
+ llvm::BasicBlock::Create(context_, "exception_unwind", func_);
+
+ // Change IRBuilder insert point
+ llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP();
+ irb_.SetInsertPoint(basic_block_unwind_);
+
+ // Pop the shadow frame
+ Expand_PopShadowFrame();
+
+ // Emit the code to return default value (zero) for the given return type.
+ char ret_shorty = oat_compilation_unit_->GetShorty()[0];
+ if (ret_shorty == 'V') {
+ irb_.CreateRetVoid();
+ } else {
+ irb_.CreateRet(irb_.getJZero(ret_shorty));
+ }
+
+ // Restore the orignal insert point for IRBuilder
+ irb_.restoreIP(irb_ip_original);
+
+ return basic_block_unwind_;
+}
+
+void GBCExpanderPass::EmitBranchExceptionLandingPad(uint32_t dex_pc) {
+ if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+ irb_.CreateBr(lpad);
+ } else {
+ irb_.CreateBr(GetUnwindBasicBlock());
+ }
+}
+
+void GBCExpanderPass::EmitGuard_ExceptionLandingPad(uint32_t dex_pc) {
+ llvm::Value* exception_pending = irb_.Runtime().EmitIsExceptionPending();
+
+ llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+ if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+ irb_.CreateCondBr(exception_pending, lpad, block_cont, kUnlikely);
+ } else {
+ irb_.CreateCondBr(exception_pending, GetUnwindBasicBlock(), block_cont, kUnlikely);
+ }
+
+ irb_.SetInsertPoint(block_cont);
+}
+
llvm::Value*
GBCExpanderPass::ExpandIntrinsic(IntrinsicHelper::IntrinsicId intr_id,
llvm::CallInst& call_inst) {
@@ -1649,75 +2095,66 @@
//==- High-level Instance ----------------------------------------------==//
case IntrinsicHelper::HLIGet: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLIGet(call_inst, kInt);
}
case IntrinsicHelper::HLIGetBoolean: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLIGet(call_inst, kBoolean);
}
case IntrinsicHelper::HLIGetByte: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLIGet(call_inst, kByte);
}
case IntrinsicHelper::HLIGetChar: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLIGet(call_inst, kChar);
}
case IntrinsicHelper::HLIGetShort: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLIGet(call_inst, kShort);
}
case IntrinsicHelper::HLIGetFloat: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLIGet(call_inst, kFloat);
}
case IntrinsicHelper::HLIGetWide: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLIGet(call_inst, kLong);
}
case IntrinsicHelper::HLIGetDouble: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLIGet(call_inst, kDouble);
}
case IntrinsicHelper::HLIGetObject: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLIGet(call_inst, kObject);
}
case IntrinsicHelper::HLIPut: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLIPut(call_inst, kInt);
return NULL;
}
case IntrinsicHelper::HLIPutBoolean: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLIPut(call_inst, kBoolean);
return NULL;
}
case IntrinsicHelper::HLIPutByte: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLIPut(call_inst, kByte);
return NULL;
}
case IntrinsicHelper::HLIPutChar: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLIPut(call_inst, kChar);
return NULL;
}
case IntrinsicHelper::HLIPutShort: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLIPut(call_inst, kShort);
return NULL;
}
case IntrinsicHelper::HLIPutFloat: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLIPut(call_inst, kFloat);
return NULL;
}
case IntrinsicHelper::HLIPutWide: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLIPut(call_inst, kLong);
return NULL;
}
case IntrinsicHelper::HLIPutDouble: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLIPut(call_inst, kDouble);
return NULL;
}
case IntrinsicHelper::HLIPutObject: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLIPut(call_inst, kObject);
return NULL;
}
@@ -1943,11 +2380,11 @@
//==- Switch -----------------------------------------------------------==//
case greenland::IntrinsicHelper::SparseSwitch: {
- UNIMPLEMENTED(FATAL);
+ // Nothing to be done.
return NULL;
}
case greenland::IntrinsicHelper::PackedSwitch: {
- UNIMPLEMENTED(FATAL);
+ // Nothing to be done.
return NULL;
}
@@ -1971,7 +2408,7 @@
//==- Method Info ------------------------------------------------------==//
case greenland::IntrinsicHelper::MethodInfo: {
- UNIMPLEMENTED(FATAL);
+ // Nothing to be done.
return NULL;
}
@@ -1979,11 +2416,8 @@
case greenland::IntrinsicHelper::CopyInt:
case greenland::IntrinsicHelper::CopyFloat:
case greenland::IntrinsicHelper::CopyLong:
- case greenland::IntrinsicHelper::CopyDouble: {
- return call_inst.getArgOperand(0);
- }
+ case greenland::IntrinsicHelper::CopyDouble:
case greenland::IntrinsicHelper::CopyObj: {
- // TODO: Update the shadow frame slots.
return call_inst.getArgOperand(0);
}