Implement SGet/SPut/AGet/APut.
Change-Id: Iab14445cce9af2d6a29b27e65212302667c3d7ed
diff --git a/src/compiler_llvm/gbc_expander.cc b/src/compiler_llvm/gbc_expander.cc
index 6e8ce12..f7b9cf2 100644
--- a/src/compiler_llvm/gbc_expander.cc
+++ b/src/compiler_llvm/gbc_expander.cc
@@ -251,9 +251,17 @@
llvm::BasicBlock* begin_bb_;
};
+ llvm::Value* EmitLoadStaticStorage(uint32_t dex_pc, uint32_t type_idx);
+
llvm::Value* Expand_HLIGet(llvm::CallInst& call_inst, JType field_jty);
void Expand_HLIPut(llvm::CallInst& call_inst, JType field_jty);
+ llvm::Value* Expand_HLSget(llvm::CallInst& call_inst, JType field_jty);
+ void Expand_HLSput(llvm::CallInst& call_inst, JType field_jty);
+
+ llvm::Value* Expand_HLArrayGet(llvm::CallInst& call_inst, JType field_jty);
+ void Expand_HLArrayPut(llvm::CallInst& call_inst, JType field_jty);
+
void EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr);
void EmitUpdateDexPC(uint32_t dex_pc);
@@ -1119,6 +1127,99 @@
}
}
+llvm::Value* GBCExpanderPass::Expand_HLArrayGet(llvm::CallInst& call_inst,
+ JType elem_jty) {
+ ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+ uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+ llvm::Value* array_addr = call_inst.getArgOperand(1);
+ llvm::Value* index_value = call_inst.getArgOperand(2);
+
+ // TODO: opt_flags
+ EmitGuard_ArrayException(dex_pc, array_addr, index_value);
+
+ llvm::Value* array_elem_addr = EmitArrayGEP(array_addr, index_value, elem_jty);
+
+ llvm::Value* array_elem_value = irb_.CreateLoad(array_elem_addr, kTBAAHeapArray, elem_jty);
+
+ switch (elem_jty) {
+ case kVoid:
+ break;
+
+ case kBoolean:
+ case kChar:
+ array_elem_value = irb_.CreateZExt(array_elem_value, irb_.getJType(elem_jty, kReg));
+ break;
+
+ case kByte:
+ case kShort:
+ array_elem_value = irb_.CreateSExt(array_elem_value, irb_.getJType(elem_jty, kReg));
+ break;
+
+ case kInt:
+ case kLong:
+ case kFloat:
+ case kDouble:
+ case kObject:
+ break;
+
+ default:
+ LOG(FATAL) << "Unknown java type: " << elem_jty;
+ }
+
+ return array_elem_value;
+}
+
+
+void GBCExpanderPass::Expand_HLArrayPut(llvm::CallInst& call_inst,
+ JType elem_jty) {
+ ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+ uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+ llvm::Value* new_value = call_inst.getArgOperand(1);
+ llvm::Value* array_addr = call_inst.getArgOperand(2);
+ llvm::Value* index_value = call_inst.getArgOperand(3);
+
+ // TODO: opt_flags
+ EmitGuard_ArrayException(dex_pc, array_addr, index_value);
+
+ switch (elem_jty) {
+ case kVoid:
+ break;
+
+ case kBoolean:
+ case kChar:
+ new_value = irb_.CreateTrunc(new_value, irb_.getJType(elem_jty, kArray));
+ break;
+
+ case kInt:
+ case kLong:
+ case kFloat:
+ case kDouble:
+ case kObject:
+ break;
+
+ default:
+ LOG(FATAL) << "Unknown java type: " << elem_jty;
+ }
+
+ llvm::Value* array_elem_addr = EmitArrayGEP(array_addr, index_value, elem_jty);
+
+ if (elem_jty == kObject) { // If put an object, check the type, and mark GC card table.
+ llvm::Function* runtime_func = irb_.GetRuntime(runtime_support::CheckPutArrayElement);
+
+ irb_.CreateCall2(runtime_func, new_value, array_addr);
+
+ EmitGuard_ExceptionLandingPad(dex_pc);
+
+ EmitMarkGCCard(new_value, array_addr);
+ }
+
+ irb_.CreateStore(new_value, array_elem_addr, kTBAAHeapArray, elem_jty);
+
+ return;
+}
+
llvm::Value* GBCExpanderPass::Expand_HLIGet(llvm::CallInst& call_inst,
JType field_jty) {
ScopedExpandToBasicBlock eb(irb_, &call_inst);
@@ -1176,7 +1277,7 @@
}
if (field_jty == kFloat || field_jty == kDouble) {
- field_value = irb_.CreateBitCast(field_value, irb_.getJType(field_jty, kReg));
+ field_value = irb_.CreateBitCast(field_value, irb_.getJType(field_jty, kAccurate));
}
return field_value;
@@ -1192,7 +1293,7 @@
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));
+ new_value = irb_.CreateBitCast(new_value, irb_.getJType(field_jty, kField));
}
// TODO: opt_flags
@@ -1248,6 +1349,222 @@
return;
}
+llvm::Value* GBCExpanderPass::EmitLoadStaticStorage(uint32_t dex_pc,
+ uint32_t type_idx) {
+ llvm::BasicBlock* block_load_static =
+ CreateBasicBlockWithDexPC(dex_pc, "load_static");
+
+ llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+ // Load static storage from dex cache
+ llvm::Value* storage_field_addr =
+ EmitLoadDexCacheStaticStorageFieldAddr(type_idx);
+
+ llvm::Value* storage_object_addr = irb_.CreateLoad(storage_field_addr, kTBAAJRuntime);
+
+ llvm::BasicBlock* block_original = irb_.GetInsertBlock();
+
+ // Test: Is the static storage of this class initialized?
+ llvm::Value* equal_null =
+ irb_.CreateICmpEQ(storage_object_addr, irb_.getJNull());
+
+ irb_.CreateCondBr(equal_null, block_load_static, block_cont, kUnlikely);
+
+ // Failback routine to load the class object
+ irb_.SetInsertPoint(block_load_static);
+
+ llvm::Function* runtime_func = irb_.GetRuntime(runtime_support::InitializeStaticStorage);
+
+ llvm::Constant* type_idx_value = irb_.getInt32(type_idx);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
+
+ EmitUpdateDexPC(dex_pc);
+
+ llvm::Value* loaded_storage_object_addr =
+ irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr);
+
+ EmitGuard_ExceptionLandingPad(dex_pc);
+
+ llvm::BasicBlock* block_after_load_static = irb_.GetInsertBlock();
+
+ irb_.CreateBr(block_cont);
+
+ // Now the class object must be loaded
+ irb_.SetInsertPoint(block_cont);
+
+ llvm::PHINode* phi = irb_.CreatePHI(irb_.getJObjectTy(), 2);
+
+ phi->addIncoming(storage_object_addr, block_original);
+ phi->addIncoming(loaded_storage_object_addr, block_after_load_static);
+
+ return phi;
+}
+
+llvm::Value* GBCExpanderPass::Expand_HLSget(llvm::CallInst& call_inst,
+ JType field_jty) {
+ ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+ uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+ uint32_t field_idx = LV2UInt(call_inst.getArgOperand(0));
+
+ int field_offset;
+ int ssb_index;
+ bool is_referrers_class;
+ bool is_volatile;
+
+ bool is_fast_path = compiler_->ComputeStaticFieldInfo(
+ field_idx, oat_compilation_unit_, field_offset, ssb_index,
+ is_referrers_class, is_volatile, false);
+
+ llvm::Value* static_field_value;
+
+ if (!is_fast_path) {
+ llvm::Function* runtime_func;
+
+ if (field_jty == kObject) {
+ runtime_func = irb_.GetRuntime(runtime_support::GetObjectStatic);
+ } else if (field_jty == kLong || field_jty == kDouble) {
+ runtime_func = irb_.GetRuntime(runtime_support::Get64Static);
+ } else {
+ runtime_func = irb_.GetRuntime(runtime_support::Get32Static);
+ }
+
+ llvm::Constant* field_idx_value = irb_.getInt32(field_idx);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ EmitUpdateDexPC(dex_pc);
+
+ static_field_value =
+ irb_.CreateCall2(runtime_func, field_idx_value, method_object_addr);
+
+ EmitGuard_ExceptionLandingPad(dex_pc);
+
+ } else {
+ DCHECK_GE(field_offset, 0);
+
+ llvm::Value* static_storage_addr = NULL;
+
+ if (is_referrers_class) {
+ // Fast path, static storage base is this method's class
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ static_storage_addr =
+ irb_.LoadFromObjectOffset(method_object_addr,
+ Method::DeclaringClassOffset().Int32Value(),
+ irb_.getJObjectTy(),
+ kTBAAConstJObject);
+ } else {
+ // Medium path, static storage base in a different class which
+ // requires checks that the other class is initialized
+ DCHECK_GE(ssb_index, 0);
+ static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index);
+ }
+
+ llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset);
+
+ llvm::Value* static_field_addr =
+ irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
+ irb_.getJType(field_jty, kField)->getPointerTo());
+
+ // TODO: Check is_volatile. We need to generate atomic load instruction
+ // when is_volatile is true.
+ static_field_value = irb_.CreateLoad(static_field_addr, kTBAAHeapStatic, field_jty);
+ }
+
+ if (field_jty == kFloat || field_jty == kDouble) {
+ static_field_value =
+ irb_.CreateBitCast(static_field_value, irb_.getJType(field_jty, kAccurate));
+ }
+
+ return static_field_value;
+}
+
+void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst,
+ JType field_jty) {
+ ScopedExpandToBasicBlock eb(irb_, &call_inst);
+
+ uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
+ uint32_t field_idx = LV2UInt(call_inst.getArgOperand(0));
+ llvm::Value* new_value = call_inst.getArgOperand(1);
+
+ if (field_jty == kFloat || field_jty == kDouble) {
+ new_value = irb_.CreateBitCast(new_value, irb_.getJType(field_jty, kField));
+ }
+
+ int field_offset;
+ int ssb_index;
+ bool is_referrers_class;
+ bool is_volatile;
+
+ bool is_fast_path = compiler_->ComputeStaticFieldInfo(
+ field_idx, oat_compilation_unit_, field_offset, ssb_index,
+ is_referrers_class, is_volatile, true);
+
+ if (!is_fast_path) {
+ llvm::Function* runtime_func;
+
+ if (field_jty == kObject) {
+ runtime_func = irb_.GetRuntime(runtime_support::SetObjectStatic);
+ } else if (field_jty == kLong || field_jty == kDouble) {
+ runtime_func = irb_.GetRuntime(runtime_support::Set64Static);
+ } else {
+ runtime_func = irb_.GetRuntime(runtime_support::Set32Static);
+ }
+
+ llvm::Constant* field_idx_value = irb_.getInt32(field_idx);
+
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ EmitUpdateDexPC(dex_pc);
+
+ irb_.CreateCall3(runtime_func, field_idx_value,
+ method_object_addr, new_value);
+
+ EmitGuard_ExceptionLandingPad(dex_pc);
+
+ } else {
+ DCHECK_GE(field_offset, 0);
+
+ llvm::Value* static_storage_addr = NULL;
+
+ if (is_referrers_class) {
+ // Fast path, static storage base is this method's class
+ llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
+
+ static_storage_addr =
+ irb_.LoadFromObjectOffset(method_object_addr,
+ Method::DeclaringClassOffset().Int32Value(),
+ irb_.getJObjectTy(),
+ kTBAAConstJObject);
+ } else {
+ // Medium path, static storage base in a different class which
+ // requires checks that the other class is initialized
+ DCHECK_GE(ssb_index, 0);
+ static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index);
+ }
+
+ llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset);
+
+ llvm::Value* static_field_addr =
+ irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
+ irb_.getJType(field_jty, kField)->getPointerTo());
+
+ // TODO: Check is_volatile. We need to generate atomic store instruction
+ // when is_volatile is true.
+ irb_.CreateStore(new_value, static_field_addr, kTBAAHeapStatic, field_jty);
+
+ if (field_jty == kObject) { // If put an object, mark the GC card table.
+ EmitMarkGCCard(new_value, static_storage_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);
@@ -2022,75 +2339,66 @@
//==- High-level Array -------------------------------------------------==//
case IntrinsicHelper::HLArrayGet: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLArrayGet(call_inst, kInt);
}
case IntrinsicHelper::HLArrayGetBoolean: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLArrayGet(call_inst, kBoolean);
}
case IntrinsicHelper::HLArrayGetByte: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLArrayGet(call_inst, kByte);
}
case IntrinsicHelper::HLArrayGetChar: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLArrayGet(call_inst, kChar);
}
case IntrinsicHelper::HLArrayGetShort: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLArrayGet(call_inst, kShort);
}
case IntrinsicHelper::HLArrayGetFloat: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLArrayGet(call_inst, kFloat);
}
case IntrinsicHelper::HLArrayGetWide: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLArrayGet(call_inst, kLong);
}
case IntrinsicHelper::HLArrayGetDouble: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLArrayGet(call_inst, kDouble);
}
case IntrinsicHelper::HLArrayGetObject: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLArrayGet(call_inst, kObject);
}
case IntrinsicHelper::HLArrayPut: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLArrayPut(call_inst, kInt);
return NULL;
}
case IntrinsicHelper::HLArrayPutBoolean: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLArrayPut(call_inst, kBoolean);
return NULL;
}
case IntrinsicHelper::HLArrayPutByte: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLArrayPut(call_inst, kByte);
return NULL;
}
case IntrinsicHelper::HLArrayPutChar: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLArrayPut(call_inst, kChar);
return NULL;
}
case IntrinsicHelper::HLArrayPutShort: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLArrayPut(call_inst, kShort);
return NULL;
}
case IntrinsicHelper::HLArrayPutFloat: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLArrayPut(call_inst, kFloat);
return NULL;
}
case IntrinsicHelper::HLArrayPutWide: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLArrayPut(call_inst, kLong);
return NULL;
}
case IntrinsicHelper::HLArrayPutDouble: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLArrayPut(call_inst, kDouble);
return NULL;
}
case IntrinsicHelper::HLArrayPutObject: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLArrayPut(call_inst, kObject);
return NULL;
}
@@ -2260,75 +2568,66 @@
//==- High-level Static ------------------------------------------------==//
case IntrinsicHelper::HLSget: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLSget(call_inst, kInt);
}
case IntrinsicHelper::HLSgetBoolean: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLSget(call_inst, kBoolean);
}
case IntrinsicHelper::HLSgetByte: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLSget(call_inst, kByte);
}
case IntrinsicHelper::HLSgetChar: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLSget(call_inst, kChar);
}
case IntrinsicHelper::HLSgetShort: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLSget(call_inst, kShort);
}
case IntrinsicHelper::HLSgetFloat: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLSget(call_inst, kFloat);
}
case IntrinsicHelper::HLSgetWide: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLSget(call_inst, kLong);
}
case IntrinsicHelper::HLSgetDouble: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLSget(call_inst, kDouble);
}
case IntrinsicHelper::HLSgetObject: {
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return Expand_HLSget(call_inst, kObject);
}
case IntrinsicHelper::HLSput: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLSput(call_inst, kInt);
return NULL;
}
case IntrinsicHelper::HLSputBoolean: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLSput(call_inst, kBoolean);
return NULL;
}
case IntrinsicHelper::HLSputByte: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLSput(call_inst, kByte);
return NULL;
}
case IntrinsicHelper::HLSputChar: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLSput(call_inst, kChar);
return NULL;
}
case IntrinsicHelper::HLSputShort: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLSput(call_inst, kShort);
return NULL;
}
case IntrinsicHelper::HLSputFloat: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLSput(call_inst, kFloat);
return NULL;
}
case IntrinsicHelper::HLSputWide: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLSput(call_inst, kLong);
return NULL;
}
case IntrinsicHelper::HLSputDouble: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLSput(call_inst, kDouble);
return NULL;
}
case IntrinsicHelper::HLSputObject: {
- UNIMPLEMENTED(FATAL);
+ Expand_HLSput(call_inst, kObject);
return NULL;
}