/* * 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. */ #ifndef ART_COMPILER_LLVM_IR_BUILDER_H_ #define ART_COMPILER_LLVM_IR_BUILDER_H_ #include "backend_types.h" #include "dex/compiler_enums.h" #include "intrinsic_helper.h" #include "md_builder.h" #include "runtime_support_builder.h" #include "runtime_support_llvm_func.h" #include <llvm/IR/Constants.h> #include <llvm/IR/DerivedTypes.h> #include <llvm/IR/IRBuilder.h> #include <llvm/IR/LLVMContext.h> #include <llvm/IR/Type.h> #include <llvm/Support/NoFolder.h> #include <stdint.h> namespace art { namespace llvm { class InserterWithDexOffset : public ::llvm::IRBuilderDefaultInserter<true> { public: InserterWithDexOffset() : node_(NULL) {} void InsertHelper(::llvm::Instruction *I, const ::llvm::Twine &Name, ::llvm::BasicBlock *BB, ::llvm::BasicBlock::iterator InsertPt) const { ::llvm::IRBuilderDefaultInserter<true>::InsertHelper(I, Name, BB, InsertPt); if (node_ != NULL) { I->setMetadata("DexOff", node_); } } void SetDexOffset(::llvm::MDNode* node) { node_ = node; } private: ::llvm::MDNode* node_; }; typedef ::llvm::IRBuilder<true, ::llvm::ConstantFolder, InserterWithDexOffset> LLVMIRBuilder; // NOTE: Here we define our own LLVMIRBuilder type alias, so that we can // switch "preserveNames" template parameter easily. class IRBuilder : public LLVMIRBuilder { public: //-------------------------------------------------------------------------- // General //-------------------------------------------------------------------------- IRBuilder(::llvm::LLVMContext& context, ::llvm::Module& module, IntrinsicHelper& intrinsic_helper); //-------------------------------------------------------------------------- // Extend load & store for TBAA //-------------------------------------------------------------------------- ::llvm::LoadInst* CreateLoad(::llvm::Value* ptr, ::llvm::MDNode* tbaa_info) { ::llvm::LoadInst* inst = LLVMIRBuilder::CreateLoad(ptr); inst->setMetadata(::llvm::LLVMContext::MD_tbaa, tbaa_info); return inst; } ::llvm::StoreInst* CreateStore(::llvm::Value* val, ::llvm::Value* ptr, ::llvm::MDNode* tbaa_info) { ::llvm::StoreInst* inst = LLVMIRBuilder::CreateStore(val, ptr); inst->setMetadata(::llvm::LLVMContext::MD_tbaa, tbaa_info); return inst; } ::llvm::AtomicCmpXchgInst* CreateAtomicCmpXchgInst(::llvm::Value* ptr, ::llvm::Value* cmp, ::llvm::Value* val, ::llvm::MDNode* tbaa_info) { ::llvm::AtomicCmpXchgInst* inst = LLVMIRBuilder::CreateAtomicCmpXchg(ptr, cmp, val, ::llvm::Acquire); inst->setMetadata(::llvm::LLVMContext::MD_tbaa, tbaa_info); return inst; } //-------------------------------------------------------------------------- // Extend memory barrier //-------------------------------------------------------------------------- void CreateMemoryBarrier(MemBarrierKind barrier_kind) { #if ANDROID_SMP // TODO: select atomic ordering according to given barrier kind. CreateFence(::llvm::SequentiallyConsistent); #endif } //-------------------------------------------------------------------------- // TBAA //-------------------------------------------------------------------------- // TODO: After we design the non-special TBAA info, re-design the TBAA interface. ::llvm::LoadInst* CreateLoad(::llvm::Value* ptr, TBAASpecialType special_ty) { return CreateLoad(ptr, mdb_.GetTBAASpecialType(special_ty)); } ::llvm::StoreInst* CreateStore(::llvm::Value* val, ::llvm::Value* ptr, TBAASpecialType special_ty) { DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!"; return CreateStore(val, ptr, mdb_.GetTBAASpecialType(special_ty)); } ::llvm::LoadInst* CreateLoad(::llvm::Value* ptr, TBAASpecialType special_ty, JType j_ty) { return CreateLoad(ptr, mdb_.GetTBAAMemoryJType(special_ty, j_ty)); } ::llvm::StoreInst* CreateStore(::llvm::Value* val, ::llvm::Value* ptr, TBAASpecialType special_ty, JType j_ty) { DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!"; return CreateStore(val, ptr, mdb_.GetTBAAMemoryJType(special_ty, j_ty)); } ::llvm::LoadInst* LoadFromObjectOffset(::llvm::Value* object_addr, int64_t offset, ::llvm::Type* type, TBAASpecialType special_ty) { return LoadFromObjectOffset(object_addr, offset, type, mdb_.GetTBAASpecialType(special_ty)); } void StoreToObjectOffset(::llvm::Value* object_addr, int64_t offset, ::llvm::Value* new_value, TBAASpecialType special_ty) { DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!"; StoreToObjectOffset(object_addr, offset, new_value, mdb_.GetTBAASpecialType(special_ty)); } ::llvm::LoadInst* LoadFromObjectOffset(::llvm::Value* object_addr, int64_t offset, ::llvm::Type* type, TBAASpecialType special_ty, JType j_ty) { return LoadFromObjectOffset(object_addr, offset, type, mdb_.GetTBAAMemoryJType(special_ty, j_ty)); } void StoreToObjectOffset(::llvm::Value* object_addr, int64_t offset, ::llvm::Value* new_value, TBAASpecialType special_ty, JType j_ty) { DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!"; StoreToObjectOffset(object_addr, offset, new_value, mdb_.GetTBAAMemoryJType(special_ty, j_ty)); } ::llvm::AtomicCmpXchgInst* CompareExchangeObjectOffset(::llvm::Value* object_addr, int64_t offset, ::llvm::Value* cmp_value, ::llvm::Value* new_value, TBAASpecialType special_ty) { DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!"; return CompareExchangeObjectOffset(object_addr, offset, cmp_value, new_value, mdb_.GetTBAASpecialType(special_ty)); } void SetTBAA(::llvm::Instruction* inst, TBAASpecialType special_ty) { inst->setMetadata(::llvm::LLVMContext::MD_tbaa, mdb_.GetTBAASpecialType(special_ty)); } //-------------------------------------------------------------------------- // Static Branch Prediction //-------------------------------------------------------------------------- // Import the orignal conditional branch using LLVMIRBuilder::CreateCondBr; ::llvm::BranchInst* CreateCondBr(::llvm::Value *cond, ::llvm::BasicBlock* true_bb, ::llvm::BasicBlock* false_bb, ExpectCond expect) { ::llvm::BranchInst* branch_inst = CreateCondBr(cond, true_bb, false_bb); if (false) { // TODO: http://b/8511695 Restore branch weight metadata branch_inst->setMetadata(::llvm::LLVMContext::MD_prof, mdb_.GetBranchWeights(expect)); } return branch_inst; } //-------------------------------------------------------------------------- // Pointer Arithmetic Helper Function //-------------------------------------------------------------------------- ::llvm::IntegerType* getPtrEquivIntTy() { return getInt32Ty(); } size_t getSizeOfPtrEquivInt() { return 4; } ::llvm::ConstantInt* getSizeOfPtrEquivIntValue() { return getPtrEquivInt(getSizeOfPtrEquivInt()); } ::llvm::ConstantInt* getPtrEquivInt(int64_t i) { return ::llvm::ConstantInt::get(getPtrEquivIntTy(), i); } ::llvm::Value* CreatePtrDisp(::llvm::Value* base, ::llvm::Value* offset, ::llvm::PointerType* ret_ty) { ::llvm::Value* base_int = CreatePtrToInt(base, getPtrEquivIntTy()); ::llvm::Value* result_int = CreateAdd(base_int, offset); ::llvm::Value* result = CreateIntToPtr(result_int, ret_ty); return result; } ::llvm::Value* CreatePtrDisp(::llvm::Value* base, ::llvm::Value* bs, ::llvm::Value* count, ::llvm::Value* offset, ::llvm::PointerType* ret_ty) { ::llvm::Value* block_offset = CreateMul(bs, count); ::llvm::Value* total_offset = CreateAdd(block_offset, offset); return CreatePtrDisp(base, total_offset, ret_ty); } ::llvm::LoadInst* LoadFromObjectOffset(::llvm::Value* object_addr, int64_t offset, ::llvm::Type* type, ::llvm::MDNode* tbaa_info) { // Convert offset to ::llvm::value ::llvm::Value* llvm_offset = getPtrEquivInt(offset); // Calculate the value's address ::llvm::Value* value_addr = CreatePtrDisp(object_addr, llvm_offset, type->getPointerTo()); // Load return CreateLoad(value_addr, tbaa_info); } void StoreToObjectOffset(::llvm::Value* object_addr, int64_t offset, ::llvm::Value* new_value, ::llvm::MDNode* tbaa_info) { // Convert offset to ::llvm::value ::llvm::Value* llvm_offset = getPtrEquivInt(offset); // Calculate the value's address ::llvm::Value* value_addr = CreatePtrDisp(object_addr, llvm_offset, new_value->getType()->getPointerTo()); // Store CreateStore(new_value, value_addr, tbaa_info); } ::llvm::AtomicCmpXchgInst* CompareExchangeObjectOffset(::llvm::Value* object_addr, int64_t offset, ::llvm::Value* cmp_value, ::llvm::Value* new_value, ::llvm::MDNode* tbaa_info) { // Convert offset to ::llvm::value ::llvm::Value* llvm_offset = getPtrEquivInt(offset); // Calculate the value's address ::llvm::Value* value_addr = CreatePtrDisp(object_addr, llvm_offset, new_value->getType()->getPointerTo()); // Atomic compare and exchange return CreateAtomicCmpXchgInst(value_addr, cmp_value, new_value, tbaa_info); } //-------------------------------------------------------------------------- // Runtime Helper Function //-------------------------------------------------------------------------- RuntimeSupportBuilder& Runtime() { return *runtime_support_; } // TODO: Deprecate ::llvm::Function* GetRuntime(runtime_support::RuntimeId rt) { return runtime_support_->GetRuntimeSupportFunction(rt); } // TODO: Deprecate void SetRuntimeSupport(RuntimeSupportBuilder* runtime_support) { // Can only set once. We can't do this on constructor, because RuntimeSupportBuilder needs // IRBuilder. if (runtime_support_ == NULL && runtime_support != NULL) { runtime_support_ = runtime_support; } } //-------------------------------------------------------------------------- // Type Helper Function //-------------------------------------------------------------------------- ::llvm::Type* getJType(char shorty_jty) { return getJType(GetJTypeFromShorty(shorty_jty)); } ::llvm::Type* getJType(JType jty); ::llvm::Type* getJVoidTy() { return getVoidTy(); } ::llvm::IntegerType* getJBooleanTy() { return getInt8Ty(); } ::llvm::IntegerType* getJByteTy() { return getInt8Ty(); } ::llvm::IntegerType* getJCharTy() { return getInt16Ty(); } ::llvm::IntegerType* getJShortTy() { return getInt16Ty(); } ::llvm::IntegerType* getJIntTy() { return getInt32Ty(); } ::llvm::IntegerType* getJLongTy() { return getInt64Ty(); } ::llvm::Type* getJFloatTy() { return getFloatTy(); } ::llvm::Type* getJDoubleTy() { return getDoubleTy(); } ::llvm::PointerType* getJObjectTy() { return java_object_type_; } ::llvm::PointerType* getJMethodTy() { return java_method_type_; } ::llvm::PointerType* getJThreadTy() { return java_thread_type_; } ::llvm::Type* getArtFrameTy() { return art_frame_type_; } ::llvm::PointerType* getJEnvTy() { return jenv_type_; } ::llvm::Type* getJValueTy() { // NOTE: JValue is an union type, which may contains boolean, byte, char, // short, int, long, float, double, Object. However, LLVM itself does // not support union type, so we have to return a type with biggest size, // then bitcast it before we use it. return getJLongTy(); } ::llvm::StructType* getShadowFrameTy(uint32_t vreg_size); //-------------------------------------------------------------------------- // Constant Value Helper Function //-------------------------------------------------------------------------- ::llvm::ConstantInt* getJBoolean(bool is_true) { return (is_true) ? getTrue() : getFalse(); } ::llvm::ConstantInt* getJByte(int8_t i) { return ::llvm::ConstantInt::getSigned(getJByteTy(), i); } ::llvm::ConstantInt* getJChar(int16_t i) { return ::llvm::ConstantInt::getSigned(getJCharTy(), i); } ::llvm::ConstantInt* getJShort(int16_t i) { return ::llvm::ConstantInt::getSigned(getJShortTy(), i); } ::llvm::ConstantInt* getJInt(int32_t i) { return ::llvm::ConstantInt::getSigned(getJIntTy(), i); } ::llvm::ConstantInt* getJLong(int64_t i) { return ::llvm::ConstantInt::getSigned(getJLongTy(), i); } ::llvm::Constant* getJFloat(float f) { return ::llvm::ConstantFP::get(getJFloatTy(), f); } ::llvm::Constant* getJDouble(double d) { return ::llvm::ConstantFP::get(getJDoubleTy(), d); } ::llvm::ConstantPointerNull* getJNull() { return ::llvm::ConstantPointerNull::get(getJObjectTy()); } ::llvm::Constant* getJZero(char shorty_jty) { return getJZero(GetJTypeFromShorty(shorty_jty)); } ::llvm::Constant* getJZero(JType jty) { switch (jty) { case kVoid: LOG(FATAL) << "Zero is not a value of void type"; return NULL; case kBoolean: return getJBoolean(false); case kByte: return getJByte(0); case kChar: return getJChar(0); case kShort: return getJShort(0); case kInt: return getJInt(0); case kLong: return getJLong(0); case kFloat: return getJFloat(0.0f); case kDouble: return getJDouble(0.0); case kObject: return getJNull(); default: LOG(FATAL) << "Unknown java type: " << jty; return NULL; } } private: ::llvm::Module* module_; MDBuilder mdb_; ::llvm::PointerType* java_object_type_; ::llvm::PointerType* java_method_type_; ::llvm::PointerType* java_thread_type_; ::llvm::PointerType* jenv_type_; ::llvm::StructType* art_frame_type_; RuntimeSupportBuilder* runtime_support_; IntrinsicHelper& intrinsic_helper_; }; } // namespace llvm } // namespace art #endif // ART_COMPILER_LLVM_IR_BUILDER_H_