diff options
Diffstat (limited to 'compiler/llvm/runtime_support_builder_thumb2.cc')
-rw-r--r-- | compiler/llvm/runtime_support_builder_thumb2.cc | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/compiler/llvm/runtime_support_builder_thumb2.cc b/compiler/llvm/runtime_support_builder_thumb2.cc new file mode 100644 index 0000000000..2b9170c4ea --- /dev/null +++ b/compiler/llvm/runtime_support_builder_thumb2.cc @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 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 "runtime_support_builder_thumb2.h" + +#include "ir_builder.h" +#include "mirror/object.h" +#include "monitor.h" +#include "thread.h" +#include "utils_llvm.h" + +#include <llvm/IR/DerivedTypes.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/InlineAsm.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Type.h> + +#include <inttypes.h> +#include <vector> + +using namespace llvm; + +namespace art { +namespace llvm { + + +void RuntimeSupportBuilderThumb2::EmitLockObject(::llvm::Value* object) { + FunctionType* func_ty = FunctionType::get(/*Result=*/irb_.getInt32Ty(), + /*Params=*/irb_.getJObjectTy(), + /*isVarArg=*/false); + // $0: result + // $1: object + // $2: temp + // $3: temp + std::string asms; + StringAppendF(&asms, "add $3, $1, #%"PRId32"\n", mirror::Object::MonitorOffset().Int32Value()); + StringAppendF(&asms, "ldr $2, [r9, #%"PRId32"]\n", Thread::ThinLockIdOffset().Int32Value()); + StringAppendF(&asms, "ldrex $0, [$3]\n"); + StringAppendF(&asms, "lsl $2, $2, %d\n", LW_LOCK_OWNER_SHIFT); + StringAppendF(&asms, "bfi $2, $0, #0, #%d\n", LW_LOCK_OWNER_SHIFT - 1); + StringAppendF(&asms, "bfc $0, #%d, #%d\n", LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1); + StringAppendF(&asms, "cmp $0, #0\n"); + StringAppendF(&asms, "it eq\n"); + StringAppendF(&asms, "strexeq $0, $2, [$3]\n"); + + InlineAsm* func = InlineAsm::get(func_ty, asms, "=&l,l,~l,~l", true); + + ::llvm::Value* retry_slow_path = irb_.CreateCall(func, object); + retry_slow_path = irb_.CreateICmpNE(retry_slow_path, irb_.getJInt(0)); + + ::llvm::Function* parent_func = irb_.GetInsertBlock()->getParent(); + BasicBlock* basic_block_lock = BasicBlock::Create(context_, "lock", parent_func); + BasicBlock* basic_block_cont = BasicBlock::Create(context_, "lock_cont", parent_func); + irb_.CreateCondBr(retry_slow_path, basic_block_lock, basic_block_cont, kUnlikely); + + irb_.SetInsertPoint(basic_block_lock); + Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject); + irb_.CreateCall2(slow_func, object, EmitGetCurrentThread()); + irb_.CreateBr(basic_block_cont); + + irb_.SetInsertPoint(basic_block_cont); + { // Memory barrier + FunctionType* asm_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_), + /*isVarArg=*/false); + InlineAsm* func = InlineAsm::get(asm_ty, "dmb sy", "", true); + irb_.CreateCall(func); + } +} + + +} // namespace llvm +} // namespace art |