diff options
Diffstat (limited to 'compiler/llvm')
27 files changed, 9830 insertions, 0 deletions
diff --git a/compiler/llvm/art_module.ll b/compiler/llvm/art_module.ll new file mode 100644 index 0000000000..233692c079 --- /dev/null +++ b/compiler/llvm/art_module.ll @@ -0,0 +1,153 @@ +;; +;; 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. +;; + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Type +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +%JavaObject = type opaque + +%ShadowFrame = type { i32 ; Number of VRegs + , %ShadowFrame* ; Previous frame + , %JavaObject* ; Method object pointer + , i32 ; Line number for stack backtrace + ; [0 x i32] ; VRegs + } + +declare void @__art_type_list(%JavaObject*, %ShadowFrame*) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Thread +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +declare %JavaObject* @art_portable_get_current_thread_from_code() +declare %JavaObject* @art_portable_set_current_thread_from_code(%JavaObject*) + +declare void @art_portable_lock_object_from_code(%JavaObject*, %JavaObject*) +declare void @art_portable_unlock_object_from_code(%JavaObject*, %JavaObject*) + +declare void @art_portable_test_suspend_from_code(%JavaObject*) + +declare %ShadowFrame* @art_portable_push_shadow_frame_from_code(%JavaObject*, %ShadowFrame*, %JavaObject*, i32) +declare void @art_portable_pop_shadow_frame_from_code(%ShadowFrame*) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Exception +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +declare %JavaObject* @art_portable_get_and_clear_exception(%JavaObject*) +declare void @art_portable_throw_div_zero_from_code() +declare void @art_portable_throw_array_bounds_from_code(i32, i32) +declare void @art_portable_throw_no_such_method_from_code(i32) +declare void @art_portable_throw_null_pointer_exception_from_code(i32) +declare void @art_portable_throw_stack_overflow_from_code() +declare void @art_portable_throw_exception_from_code(%JavaObject*) + +declare i32 @art_portable_find_catch_block_from_code(%JavaObject*, i32) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Object Space +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +declare %JavaObject* @art_portable_alloc_object_from_code(i32, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_alloc_object_from_code_with_access_check(i32, %JavaObject*, %JavaObject*) + +declare %JavaObject* @art_portable_alloc_array_from_code(i32, %JavaObject*, i32, %JavaObject*) +declare %JavaObject* @art_portable_alloc_array_from_code_with_access_check(i32, %JavaObject*, i32, %JavaObject*) +declare %JavaObject* @art_portable_check_and_alloc_array_from_code(i32, %JavaObject*, i32, %JavaObject*) +declare %JavaObject* @art_portable_check_and_alloc_array_from_code_with_access_check(i32, %JavaObject*, i32, %JavaObject*) + +declare void @art_portable_find_instance_field_from_code(i32, %JavaObject*) +declare void @art_portable_find_static_field_from_code(i32, %JavaObject*) + +declare %JavaObject* @art_portable_find_static_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_find_direct_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_find_virtual_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_find_super_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_find_interface_method_from_code_with_access_check(i32, %JavaObject*, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_find_interface_method_from_code(i32, %JavaObject*, %JavaObject*, %JavaObject*) + +declare %JavaObject* @art_portable_initialize_static_storage_from_code(i32, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_initialize_type_from_code(i32, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_initialize_type_and_verify_access_from_code(i32, %JavaObject*, %JavaObject*) + +declare %JavaObject* @art_portable_resolve_string_from_code(%JavaObject*, i32) + +declare i32 @art_portable_set32_static_from_code(i32, %JavaObject*, i32) +declare i32 @art_portable_set64_static_from_code(i32, %JavaObject*, i64) +declare i32 @art_portable_set_obj_static_from_code(i32, %JavaObject*, %JavaObject*) + +declare i32 @art_portable_get32_static_from_code(i32, %JavaObject*) +declare i64 @art_portable_get64_static_from_code(i32, %JavaObject*) +declare %JavaObject* @art_portable_get_obj_static_from_code(i32, %JavaObject*) + +declare i32 @art_portable_set32_instance_from_code(i32, %JavaObject*, %JavaObject*, i32) +declare i32 @art_portable_set64_instance_from_code(i32, %JavaObject*, %JavaObject*, i64) +declare i32 @art_portable_set_obj_instance_from_code(i32, %JavaObject*, %JavaObject*, %JavaObject*) + +declare i32 @art_portable_get32_instance_from_code(i32, %JavaObject*, %JavaObject*) +declare i64 @art_portable_get64_instance_from_code(i32, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_get_obj_instance_from_code(i32, %JavaObject*, %JavaObject*) + +declare %JavaObject* @art_portable_decode_jobject_in_thread(%JavaObject*, %JavaObject*) + +declare void @art_portable_fill_array_data_from_code(%JavaObject*, i32, %JavaObject*, i32) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Type Checking, in the nature of casting +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +declare i32 @art_portable_is_assignable_from_code(%JavaObject*, %JavaObject*) +declare void @art_portable_check_cast_from_code(%JavaObject*, %JavaObject*) +declare void @art_portable_check_put_array_element_from_code(%JavaObject*, %JavaObject*) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Math +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +declare i64 @art_d2l(double) +declare i32 @art_d2i(double) +declare i64 @art_f2l(float) +declare i32 @art_f2i(float) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; JNI +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +declare i32 @art_portable_jni_method_start(%JavaObject*) +declare i32 @art_portable_jni_method_start_synchronized(%JavaObject*, %JavaObject*) + +declare void @art_portable_jni_method_end(i32, %JavaObject*) +declare void @art_portable_jni_method_end_synchronized(i32, %JavaObject*, %JavaObject*) +declare %JavaObject* @art_portable_jni_method_end_with_reference(%JavaObject*, i32, %JavaObject*) +declare %JavaObject* @art_portable_jni_method_end_with_reference_synchronized(%JavaObject*, i32, %JavaObject*, %JavaObject*) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Temporary runtime support, will be removed in the future +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +declare i1 @art_portable_is_exception_pending_from_code() + +declare void @art_portable_mark_gc_card_from_code(%JavaObject*, %JavaObject*) + +declare void @art_portable_proxy_invoke_handler_from_code(%JavaObject*, ...) diff --git a/compiler/llvm/backend_options.h b/compiler/llvm/backend_options.h new file mode 100644 index 0000000000..924a34639c --- /dev/null +++ b/compiler/llvm/backend_options.h @@ -0,0 +1,50 @@ +/* + * 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_SRC_COMPILER_LLVM_BACKEND_OPTIONS_H_ +#define ART_SRC_COMPILER_LLVM_BACKEND_OPTIONS_H_ + +#include <llvm/Support/CommandLine.h> + +#define DECLARE_ARM_BACKEND_OPTIONS \ +extern llvm::cl::opt<bool> EnableARMLongCalls; \ +extern llvm::cl::opt<bool> ReserveR9; + +#define INITIAL_ARM_BACKEND_OPTIONS \ +EnableARMLongCalls = true; \ +ReserveR9 = true; + +#define DECLARE_X86_BACKEND_OPTIONS +#define INITIAL_X86_BACKEND_OPTIONS + +#define DECLARE_Mips_BACKEND_OPTIONS +#define INITIAL_Mips_BACKEND_OPTIONS + +#define LLVM_TARGET(TargetName) DECLARE_##TargetName##_BACKEND_OPTIONS +#include "llvm/Config/Targets.def" + +namespace art { +namespace llvm { + +inline void InitialBackendOptions() { +#define LLVM_TARGET(TargetName) INITIAL_##TargetName##_BACKEND_OPTIONS +#include "llvm/Config/Targets.def" +} + +} // namespace llvm +} // namespace art + +#endif // ART_SRC_COMPILER_LLVM_BACKEND_OPTIONS_H_ diff --git a/compiler/llvm/backend_types.h b/compiler/llvm/backend_types.h new file mode 100644 index 0000000000..c89504a859 --- /dev/null +++ b/compiler/llvm/backend_types.h @@ -0,0 +1,104 @@ +/* + * 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_SRC_COMPILER_LLVM_BACKEND_TYPES_H_ +#define ART_SRC_COMPILER_LLVM_BACKEND_TYPES_H_ + +#include "base/logging.h" + + +namespace art { +namespace llvm { + + +enum JType { + kVoid, + kBoolean, + kByte, + kChar, + kShort, + kInt, + kLong, + kFloat, + kDouble, + kObject, + MAX_JTYPE +}; + +enum TBAASpecialType { + kTBAARegister, + kTBAAStackTemp, + kTBAAHeapArray, + kTBAAHeapInstance, + kTBAAHeapStatic, + kTBAAJRuntime, + kTBAARuntimeInfo, + kTBAAShadowFrame, + kTBAAConstJObject, + MAX_TBAA_SPECIAL_TYPE +}; + + +enum ExpectCond { + kLikely, + kUnlikely, + MAX_EXPECT +}; + + +inline JType GetJTypeFromShorty(char shorty_jty) { + switch (shorty_jty) { + case 'V': + return kVoid; + + case 'Z': + return kBoolean; + + case 'B': + return kByte; + + case 'C': + return kChar; + + case 'S': + return kShort; + + case 'I': + return kInt; + + case 'J': + return kLong; + + case 'F': + return kFloat; + + case 'D': + return kDouble; + + case 'L': + return kObject; + + default: + LOG(FATAL) << "Unknown Dalvik shorty descriptor: " << shorty_jty; + return kVoid; + } +} + +} // namespace llvm +} // namespace art + + +#endif // ART_SRC_COMPILER_LLVM_BACKEND_TYPES_H_ diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc new file mode 100644 index 0000000000..afca223192 --- /dev/null +++ b/compiler/llvm/compiler_llvm.cc @@ -0,0 +1,239 @@ +/* + * 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 "compiler_llvm.h" + +#include "backend_options.h" +#include "base/stl_util.h" +#include "class_linker.h" +#include "compiled_method.h" +#include "driver/compiler_driver.h" +#include "driver/dex_compilation_unit.h" +#include "globals.h" +#include "ir_builder.h" +#include "jni/portable/jni_compiler.h" +#include "llvm_compilation_unit.h" +#include "oat_file.h" +#include "utils_llvm.h" +#include "verifier/method_verifier.h" + +#include <llvm/LinkAllPasses.h> +#include <llvm/Support/ManagedStatic.h> +#include <llvm/Support/TargetSelect.h> +#include <llvm/Support/Threading.h> + +namespace art { +void CompileOneMethod(CompilerDriver& driver, + const CompilerBackend compilerBackend, + const DexFile::CodeItem* code_item, + uint32_t access_flags, InvokeType invoke_type, + uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + const DexFile& dex_file, + llvm::LlvmCompilationUnit* llvm_info); +} + +namespace llvm { + extern bool TimePassesIsEnabled; +} + +namespace { + +pthread_once_t llvm_initialized = PTHREAD_ONCE_INIT; + +void InitializeLLVM() { + // Initialize LLVM internal data structure for multithreading + llvm::llvm_start_multithreaded(); + + // NOTE: Uncomment following line to show the time consumption of LLVM passes + //llvm::TimePassesIsEnabled = true; + + // Initialize LLVM target-specific options. + art::llvm::InitialBackendOptions(); + + // Initialize LLVM target, MC subsystem, asm printer, and asm parser. + if (art::kIsTargetBuild) { + // Don't initialize all targets on device. Just initialize the device's native target + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::InitializeNativeTargetAsmParser(); + } else { + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllAsmParsers(); + } + + // Initialize LLVM optimization passes + llvm::PassRegistry ®istry = *llvm::PassRegistry::getPassRegistry(); + + llvm::initializeCore(registry); + llvm::initializeScalarOpts(registry); + llvm::initializeIPO(registry); + llvm::initializeAnalysis(registry); + llvm::initializeIPA(registry); + llvm::initializeTransformUtils(registry); + llvm::initializeInstCombine(registry); + llvm::initializeInstrumentation(registry); + llvm::initializeTarget(registry); +} + +// The Guard to Shutdown LLVM +// llvm::llvm_shutdown_obj llvm_guard; +// TODO: We are commenting out this line because this will cause SEGV from +// time to time. +// Two reasons: (1) the order of the destruction of static objects, or +// (2) dlopen/dlclose side-effect on static objects. + +} // anonymous namespace + + +namespace art { +namespace llvm { + + +::llvm::Module* makeLLVMModuleContents(::llvm::Module* module); + + +CompilerLLVM::CompilerLLVM(CompilerDriver* driver, InstructionSet insn_set) + : compiler_driver_(driver), insn_set_(insn_set), + next_cunit_id_lock_("compilation unit id lock"), next_cunit_id_(1) { + + // Initialize LLVM libraries + pthread_once(&llvm_initialized, InitializeLLVM); +} + + +CompilerLLVM::~CompilerLLVM() { +} + + +LlvmCompilationUnit* CompilerLLVM::AllocateCompilationUnit() { + MutexLock GUARD(Thread::Current(), next_cunit_id_lock_); + LlvmCompilationUnit* cunit = new LlvmCompilationUnit(this, next_cunit_id_++); + if (!bitcode_filename_.empty()) { + cunit->SetBitcodeFileName(StringPrintf("%s-%zu", + bitcode_filename_.c_str(), + cunit->GetCompilationUnitId())); + } + return cunit; +} + + +CompiledMethod* CompilerLLVM:: +CompileDexMethod(DexCompilationUnit* dex_compilation_unit, InvokeType invoke_type) { + UniquePtr<LlvmCompilationUnit> cunit(AllocateCompilationUnit()); + + cunit->SetDexCompilationUnit(dex_compilation_unit); + cunit->SetCompilerDriver(compiler_driver_); + // TODO: consolidate ArtCompileMethods + CompileOneMethod(*compiler_driver_, + kPortable, + dex_compilation_unit->GetCodeItem(), + dex_compilation_unit->GetAccessFlags(), + invoke_type, + dex_compilation_unit->GetClassDefIndex(), + dex_compilation_unit->GetDexMethodIndex(), + dex_compilation_unit->GetClassLoader(), + *dex_compilation_unit->GetDexFile(), + cunit.get()); + + cunit->Materialize(); + + MethodReference mref(dex_compilation_unit->GetDexFile(), + dex_compilation_unit->GetDexMethodIndex()); + return new CompiledMethod(compiler_driver_->GetInstructionSet(), + cunit->GetElfObject(), + *verifier::MethodVerifier::GetDexGcMap(mref), + cunit->GetDexCompilationUnit()->GetSymbol()); +} + + +CompiledMethod* CompilerLLVM:: +CompileNativeMethod(DexCompilationUnit* dex_compilation_unit) { + UniquePtr<LlvmCompilationUnit> cunit(AllocateCompilationUnit()); + + UniquePtr<JniCompiler> jni_compiler( + new JniCompiler(cunit.get(), *compiler_driver_, dex_compilation_unit)); + + return jni_compiler->Compile(); +} + + +} // namespace llvm +} // namespace art + +inline static art::llvm::CompilerLLVM* ContextOf(art::CompilerDriver& driver) { + void *compiler_context = driver.GetCompilerContext(); + CHECK(compiler_context != NULL); + return reinterpret_cast<art::llvm::CompilerLLVM*>(compiler_context); +} + +inline static const art::llvm::CompilerLLVM* ContextOf(const art::CompilerDriver& driver) { + void *compiler_context = driver.GetCompilerContext(); + CHECK(compiler_context != NULL); + return reinterpret_cast<const art::llvm::CompilerLLVM*>(compiler_context); +} + +extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver) { + CHECK(driver.GetCompilerContext() == NULL); + + art::llvm::CompilerLLVM* compiler_llvm = new art::llvm::CompilerLLVM(&driver, + driver.GetInstructionSet()); + + driver.SetCompilerContext(compiler_llvm); +} + +extern "C" void ArtUnInitCompilerContext(art::CompilerDriver& driver) { + delete ContextOf(driver); + driver.SetCompilerContext(NULL); +} +extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, + const art::DexFile::CodeItem* code_item, + uint32_t access_flags, + art::InvokeType invoke_type, + uint32_t class_def_idx, + uint32_t method_idx, + jobject class_loader, + const art::DexFile& dex_file) { + UNUSED(class_def_idx); // TODO: this is used with Compiler::RequiresConstructorBarrier. + art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker(); + + art::DexCompilationUnit dex_compilation_unit( + NULL, class_loader, class_linker, dex_file, code_item, + class_def_idx, method_idx, access_flags); + art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver); + art::CompiledMethod* result = compiler_llvm->CompileDexMethod(&dex_compilation_unit, invoke_type); + return result; +} + +extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& driver, + uint32_t access_flags, uint32_t method_idx, + const art::DexFile& dex_file) { + art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker(); + + art::DexCompilationUnit dex_compilation_unit( + NULL, NULL, class_linker, dex_file, NULL, + 0, method_idx, access_flags); + + art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver); + art::CompiledMethod* result = compiler_llvm->CompileNativeMethod(&dex_compilation_unit); + return result; +} + +extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver, + std::string const& filename) { + ContextOf(driver)->SetBitcodeFileName(filename); +} diff --git a/compiler/llvm/compiler_llvm.h b/compiler/llvm/compiler_llvm.h new file mode 100644 index 0000000000..b70ddc5e20 --- /dev/null +++ b/compiler/llvm/compiler_llvm.h @@ -0,0 +1,103 @@ +/* + * 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_SRC_COMPILER_LLVM_COMPILER_LLVM_H_ +#define ART_SRC_COMPILER_LLVM_COMPILER_LLVM_H_ + +#include "base/macros.h" +#include "dex_file.h" +#include "driver/compiler_driver.h" +#include "instruction_set.h" +#include "mirror/object.h" + +#include <UniquePtr.h> + +#include <string> +#include <utility> +#include <vector> + +namespace art { + class CompiledMethod; + class CompilerDriver; + class DexCompilationUnit; + namespace mirror { + class AbstractMethod; + class ClassLoader; + } // namespace mirror +} // namespace art + + +namespace llvm { + class Function; + class LLVMContext; + class Module; + class PointerType; + class StructType; + class Type; +} // namespace llvm + + +namespace art { +namespace llvm { + +class LlvmCompilationUnit; +class IRBuilder; + +class CompilerLLVM { + public: + CompilerLLVM(CompilerDriver* driver, InstructionSet insn_set); + + ~CompilerLLVM(); + + CompilerDriver* GetCompiler() const { + return compiler_driver_; + } + + InstructionSet GetInstructionSet() const { + return insn_set_; + } + + void SetBitcodeFileName(std::string const& filename) { + bitcode_filename_ = filename; + } + + CompiledMethod* CompileDexMethod(DexCompilationUnit* dex_compilation_unit, + InvokeType invoke_type); + + CompiledMethod* CompileGBCMethod(DexCompilationUnit* dex_compilation_unit, std::string* func); + + CompiledMethod* CompileNativeMethod(DexCompilationUnit* dex_compilation_unit); + + private: + LlvmCompilationUnit* AllocateCompilationUnit(); + + CompilerDriver* const compiler_driver_; + + const InstructionSet insn_set_; + + Mutex next_cunit_id_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + size_t next_cunit_id_ GUARDED_BY(next_cunit_id_lock_); + + std::string bitcode_filename_; + + DISALLOW_COPY_AND_ASSIGN(CompilerLLVM); +}; + + +} // namespace llvm +} // namespace art + +#endif // ART_SRC_COMPILER_LLVM_COMPILER_LLVM_H_ diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc new file mode 100644 index 0000000000..b139e322f1 --- /dev/null +++ b/compiler/llvm/gbc_expander.cc @@ -0,0 +1,3753 @@ +/* + * 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 "dex_file-inl.h" +#include "driver/compiler_driver.h" +#include "driver/dex_compilation_unit.h" +#include "intrinsic_helper.h" +#include "ir_builder.h" +#include "method_reference.h" +#include "mirror/abstract_method.h" +#include "mirror/array.h" +#include "mirror/string.h" +#include "thread.h" +#include "utils_llvm.h" +#include "verifier/method_verifier.h" + +#include "dex/compiler_ir.h" +#include "dex/mir_graph.h" +#include "dex/quick/mir_to_lir.h" +using art::kMIRIgnoreNullCheck; +using art::kMIRIgnoreRangeCheck; + +#include <llvm/ADT/STLExtras.h> +#include <llvm/IR/Intrinsics.h> +#include <llvm/IR/Metadata.h> +#include <llvm/Pass.h> +#include <llvm/Support/CFG.h> +#include <llvm/Support/InstIterator.h> + +#include <vector> +#include <map> +#include <utility> + +using namespace art::llvm; + +using art::llvm::IntrinsicHelper; + +namespace art { +extern char RemapShorty(char shortyType); +}; + +namespace { + +class GBCExpanderPass : public llvm::FunctionPass { + private: + const IntrinsicHelper& intrinsic_helper_; + IRBuilder& irb_; + + llvm::LLVMContext& context_; + RuntimeSupportBuilder& rtb_; + + private: + llvm::AllocaInst* shadow_frame_; + llvm::Value* old_shadow_frame_; + + private: + art::CompilerDriver* const driver_; + + const art::DexCompilationUnit* const dex_compilation_unit_; + + llvm::Function* func_; + + std::vector<llvm::BasicBlock*> basic_blocks_; + + std::vector<llvm::BasicBlock*> basic_block_landing_pads_; + llvm::BasicBlock* current_bb_; + std::map<llvm::BasicBlock*, std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock*> > > + landing_pad_phi_mapping_; + llvm::BasicBlock* basic_block_unwind_; + + // Maps each vreg to its shadow frame address. + std::vector<llvm::Value*> shadow_frame_vreg_addresses_; + + bool changed_; + + private: + //---------------------------------------------------------------------------- + // Constant for GBC expansion + //---------------------------------------------------------------------------- + enum IntegerShiftKind { + kIntegerSHL, + kIntegerSHR, + kIntegerUSHR, + }; + + private: + //---------------------------------------------------------------------------- + // Helper function for GBC expansion + //---------------------------------------------------------------------------- + + 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. + + void EmitStackOverflowCheck(llvm::Instruction* first_non_alloca); + + void RewriteFunction(); + + void RewriteBasicBlock(llvm::BasicBlock* original_block); + + void UpdatePhiInstruction(llvm::BasicBlock* old_basic_block, + llvm::BasicBlock* new_basic_block); + + + // Sign or zero extend category 1 types < 32bits in size to 32bits. + llvm::Value* SignOrZeroExtendCat1Types(llvm::Value* value, JType jty); + + // Truncate category 1 types from 32bits to the given JType size. + llvm::Value* TruncateCat1Types(llvm::Value* value, JType jty); + + //---------------------------------------------------------------------------- + // Dex cache code generation helper function + //---------------------------------------------------------------------------- + llvm::Value* EmitLoadDexCacheAddr(art::MemberOffset dex_cache_offset); + + llvm::Value* EmitLoadDexCacheStaticStorageFieldAddr(uint32_t type_idx); + + llvm::Value* EmitLoadDexCacheResolvedTypeFieldAddr(uint32_t type_idx); + + llvm::Value* EmitLoadDexCacheResolvedMethodFieldAddr(uint32_t method_idx); + + llvm::Value* EmitLoadDexCacheStringFieldAddr(uint32_t string_idx); + + //---------------------------------------------------------------------------- + // Code generation helper function + //---------------------------------------------------------------------------- + llvm::Value* EmitLoadMethodObjectAddr(); + + llvm::Value* EmitLoadArrayLength(llvm::Value* array); + + llvm::Value* EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx); + + llvm::Value* EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx, + llvm::Value* this_addr); + + llvm::Value* EmitArrayGEP(llvm::Value* array_addr, + llvm::Value* index_value, + JType elem_jty); + + //---------------------------------------------------------------------------- + // Invoke helper function + //---------------------------------------------------------------------------- + llvm::Value* EmitInvoke(llvm::CallInst& call_inst); + + //---------------------------------------------------------------------------- + // Inlining helper functions + //---------------------------------------------------------------------------- + bool EmitIntrinsic(llvm::CallInst& call_inst, llvm::Value** result); + + bool EmitIntrinsicStringLengthOrIsEmpty(llvm::CallInst& call_inst, + llvm::Value** result, bool is_empty); + + private: + //---------------------------------------------------------------------------- + // Expand Greenland intrinsics + //---------------------------------------------------------------------------- + void Expand_TestSuspend(llvm::CallInst& call_inst); + + void Expand_MarkGCCard(llvm::CallInst& call_inst); + + llvm::Value* Expand_LoadStringFromDexCache(llvm::Value* string_idx_value); + + llvm::Value* Expand_LoadTypeFromDexCache(llvm::Value* type_idx_value); + + void Expand_LockObject(llvm::Value* obj); + + void Expand_UnlockObject(llvm::Value* obj); + + llvm::Value* Expand_ArrayGet(llvm::Value* array_addr, + llvm::Value* index_value, + JType elem_jty); + + void Expand_ArrayPut(llvm::Value* new_value, + llvm::Value* array_addr, + llvm::Value* index_value, + JType elem_jty); + + void Expand_FilledNewArray(llvm::CallInst& call_inst); + + llvm::Value* Expand_IGetFast(llvm::Value* field_offset_value, + llvm::Value* is_volatile_value, + llvm::Value* object_addr, + JType field_jty); + + void Expand_IPutFast(llvm::Value* field_offset_value, + llvm::Value* is_volatile_value, + llvm::Value* object_addr, + llvm::Value* new_value, + JType field_jty); + + llvm::Value* Expand_SGetFast(llvm::Value* static_storage_addr, + llvm::Value* field_offset_value, + llvm::Value* is_volatile_value, + JType field_jty); + + void Expand_SPutFast(llvm::Value* static_storage_addr, + llvm::Value* field_offset_value, + llvm::Value* is_volatile_value, + llvm::Value* new_value, + JType field_jty); + + llvm::Value* Expand_LoadDeclaringClassSSB(llvm::Value* method_object_addr); + + llvm::Value* Expand_LoadClassSSBFromDexCache(llvm::Value* type_idx_value); + + llvm::Value* + Expand_GetSDCalleeMethodObjAddrFast(llvm::Value* callee_method_idx_value); + + llvm::Value* + Expand_GetVirtualCalleeMethodObjAddrFast(llvm::Value* vtable_idx_value, + llvm::Value* this_addr); + + llvm::Value* Expand_Invoke(llvm::CallInst& call_inst); + + llvm::Value* Expand_DivRem(llvm::CallInst& call_inst, bool is_div, JType op_jty); + + void Expand_AllocaShadowFrame(llvm::Value* num_vregs_value); + + void Expand_SetVReg(llvm::Value* entry_idx, llvm::Value* obj); + + void Expand_PopShadowFrame(); + + void Expand_UpdateDexPC(llvm::Value* dex_pc_value); + + //---------------------------------------------------------------------------- + // Quick + //---------------------------------------------------------------------------- + + llvm::Value* Expand_FPCompare(llvm::Value* src1_value, + llvm::Value* src2_value, + bool gt_bias); + + llvm::Value* Expand_LongCompare(llvm::Value* src1_value, llvm::Value* src2_value); + + llvm::Value* EmitCompareResultSelection(llvm::Value* cmp_eq, + llvm::Value* cmp_lt); + + llvm::Value* EmitLoadConstantClass(uint32_t dex_pc, uint32_t type_idx); + 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); + + llvm::Value* Expand_ConstString(llvm::CallInst& call_inst); + llvm::Value* Expand_ConstClass(llvm::CallInst& call_inst); + + void Expand_MonitorEnter(llvm::CallInst& call_inst); + void Expand_MonitorExit(llvm::CallInst& call_inst); + + void Expand_HLCheckCast(llvm::CallInst& call_inst); + llvm::Value* Expand_InstanceOf(llvm::CallInst& call_inst); + + llvm::Value* Expand_NewInstance(llvm::CallInst& call_inst); + + llvm::Value* Expand_HLInvoke(llvm::CallInst& call_inst); + + llvm::Value* Expand_OptArrayLength(llvm::CallInst& call_inst); + llvm::Value* Expand_NewArray(llvm::CallInst& call_inst); + llvm::Value* Expand_HLFilledNewArray(llvm::CallInst& call_inst); + void Expand_HLFillArrayData(llvm::CallInst& call_inst); + + llvm::Value* EmitAllocNewArray(uint32_t dex_pc, + llvm::Value* array_length_value, + uint32_t type_idx, + bool is_filled_new_array); + + llvm::Value* EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx, + art::InvokeType invoke_type, + llvm::Value* this_addr, + uint32_t dex_pc, + bool is_fast_path); + + 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, + int opt_flags); + + void EmitGuard_ArrayIndexOutOfBoundsException(uint32_t dex_pc, + llvm::Value* array, + llvm::Value* index, + int opt_flags); + + llvm::FunctionType* GetFunctionType(llvm::Type* ret_type, 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 + //---------------------------------------------------------------------------- + + llvm::Value* Expand_IntegerShift(llvm::Value* src1_value, + llvm::Value* src2_value, + IntegerShiftKind kind, + JType op_jty); + + public: + static char ID; + + GBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb, + art::CompilerDriver* driver, const art::DexCompilationUnit* dex_compilation_unit) + : llvm::FunctionPass(ID), intrinsic_helper_(intrinsic_helper), irb_(irb), + context_(irb.getContext()), rtb_(irb.Runtime()), + shadow_frame_(NULL), old_shadow_frame_(NULL), + driver_(driver), + dex_compilation_unit_(dex_compilation_unit), + func_(NULL), current_bb_(NULL), basic_block_unwind_(NULL), changed_(false) {} + + bool runOnFunction(llvm::Function& func); + + private: + void InsertStackOverflowCheck(llvm::Function& func); + + llvm::Value* ExpandIntrinsic(IntrinsicHelper::IntrinsicId intr_id, + llvm::CallInst& call_inst); + +}; + +char GBCExpanderPass::ID = 0; + +bool GBCExpanderPass::runOnFunction(llvm::Function& func) { + VLOG(compiler) << "GBC expansion on " << func.getName().str(); + + // Runtime support or stub + if (dex_compilation_unit_ == NULL) { + return false; + } + + // Setup rewrite context + shadow_frame_ = NULL; + old_shadow_frame_ = NULL; + func_ = &func; + changed_ = false; // Assume unchanged + + shadow_frame_vreg_addresses_.resize(dex_compilation_unit_->GetCodeItem()->registers_size_, NULL); + basic_blocks_.resize(dex_compilation_unit_->GetCodeItem()->insns_size_in_code_units_); + basic_block_landing_pads_.resize(dex_compilation_unit_->GetCodeItem()->tries_size_, NULL); + basic_block_unwind_ = NULL; + for (llvm::Function::iterator bb_iter = func_->begin(), bb_end = func_->end(); + bb_iter != bb_end; + ++bb_iter) { + if (bb_iter->begin()->getMetadata("DexOff") == NULL) { + continue; + } + uint32_t dex_pc = LV2UInt(bb_iter->begin()->getMetadata("DexOff")->getOperand(0)); + basic_blocks_[dex_pc] = bb_iter; + } + + // Insert stack overflow check + InsertStackOverflowCheck(func); // TODO: Use intrinsic. + + // Rewrite the intrinsics + RewriteFunction(); + + VERIFY_LLVM_FUNCTION(func); + + return changed_; +} + +void GBCExpanderPass::RewriteBasicBlock(llvm::BasicBlock* original_block) { + llvm::BasicBlock* curr_basic_block = original_block; + + llvm::BasicBlock::iterator inst_iter = original_block->begin(); + llvm::BasicBlock::iterator inst_end = original_block->end(); + + while (inst_iter != inst_end) { + llvm::CallInst* call_inst = llvm::dyn_cast<llvm::CallInst>(inst_iter); + IntrinsicHelper::IntrinsicId intr_id = IntrinsicHelper::UnknownId; + + if (call_inst) { + llvm::Function* callee_func = call_inst->getCalledFunction(); + intr_id = intrinsic_helper_.GetIntrinsicId(callee_func); + } + + if (intr_id == IntrinsicHelper::UnknownId) { + // This is not intrinsic call. Skip this instruction. + ++inst_iter; + continue; + } + + // Rewrite the intrinsic and change the function + changed_ = true; + irb_.SetInsertPoint(inst_iter); + + // Expand the intrinsic + if (llvm::Value* new_value = ExpandIntrinsic(intr_id, *call_inst)) { + inst_iter->replaceAllUsesWith(new_value); + } + + // Remove the old intrinsic call instruction + llvm::BasicBlock::iterator old_inst = inst_iter++; + old_inst->eraseFromParent(); + + // Splice the instruction to the new basic block + llvm::BasicBlock* next_basic_block = irb_.GetInsertBlock(); + if (next_basic_block != curr_basic_block) { + next_basic_block->getInstList().splice( + irb_.GetInsertPoint(), curr_basic_block->getInstList(), + inst_iter, inst_end); + curr_basic_block = next_basic_block; + inst_end = curr_basic_block->end(); + } + } +} + + +void GBCExpanderPass::RewriteFunction() { + size_t num_basic_blocks = func_->getBasicBlockList().size(); + // NOTE: We are not using (bb_iter != bb_end) as the for-loop condition, + // because we will create new basic block while expanding the intrinsics. + // We only want to iterate through the input basic blocks. + + landing_pad_phi_mapping_.clear(); + + for (llvm::Function::iterator bb_iter = func_->begin(); + num_basic_blocks > 0; ++bb_iter, --num_basic_blocks) { + // Set insert point to current basic block. + irb_.SetInsertPoint(bb_iter); + + current_bb_ = bb_iter; + + // Rewrite the basic block + RewriteBasicBlock(bb_iter); + + // Update the phi-instructions in the successor basic block + llvm::BasicBlock* last_block = irb_.GetInsertBlock(); + if (last_block != bb_iter) { + UpdatePhiInstruction(bb_iter, last_block); + } + } + + typedef std::map<llvm::PHINode*, llvm::PHINode*> HandlerPHIMap; + HandlerPHIMap handler_phi; + // Iterate every used landing pad basic block + for (size_t i = 0, ei = basic_block_landing_pads_.size(); i != ei; ++i) { + llvm::BasicBlock* lbb = basic_block_landing_pads_[i]; + if (lbb == NULL) { + continue; + } + + llvm::TerminatorInst* term_inst = lbb->getTerminator(); + std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock*> >& rewrite_pair + = landing_pad_phi_mapping_[lbb]; + irb_.SetInsertPoint(lbb->begin()); + + // Iterate every succeeding basic block (catch block) + for (unsigned succ_iter = 0, succ_end = term_inst->getNumSuccessors(); + succ_iter != succ_end; ++succ_iter) { + llvm::BasicBlock* succ_basic_block = term_inst->getSuccessor(succ_iter); + + // Iterate every phi instructions in the succeeding basic block + for (llvm::BasicBlock::iterator + inst_iter = succ_basic_block->begin(), + inst_end = succ_basic_block->end(); + inst_iter != inst_end; ++inst_iter) { + llvm::PHINode *phi = llvm::dyn_cast<llvm::PHINode>(inst_iter); + + if (!phi) { + break; // Meet non-phi instruction. Done. + } + + if (handler_phi[phi] == NULL) { + handler_phi[phi] = llvm::PHINode::Create(phi->getType(), 1); + } + + // Create new_phi in landing pad + llvm::PHINode* new_phi = irb_.CreatePHI(phi->getType(), rewrite_pair.size()); + // Insert all incoming value into new_phi by rewrite_pair + for (size_t j = 0, ej = rewrite_pair.size(); j != ej; ++j) { + llvm::BasicBlock* old_bb = rewrite_pair[j].first; + llvm::BasicBlock* new_bb = rewrite_pair[j].second; + new_phi->addIncoming(phi->getIncomingValueForBlock(old_bb), new_bb); + } + // Delete all incoming value from phi by rewrite_pair + for (size_t j = 0, ej = rewrite_pair.size(); j != ej; ++j) { + llvm::BasicBlock* old_bb = rewrite_pair[j].first; + int old_bb_idx = phi->getBasicBlockIndex(old_bb); + if (old_bb_idx >= 0) { + phi->removeIncomingValue(old_bb_idx, false); + } + } + // Insert new_phi into new handler phi + handler_phi[phi]->addIncoming(new_phi, lbb); + } + } + } + + // Replace all handler phi + // We can't just use the old handler phi, because some exception edges will disappear after we + // compute fast-path. + for (HandlerPHIMap::iterator it = handler_phi.begin(); it != handler_phi.end(); ++it) { + llvm::PHINode* old_phi = it->first; + llvm::PHINode* new_phi = it->second; + new_phi->insertBefore(old_phi); + old_phi->replaceAllUsesWith(new_phi); + old_phi->eraseFromParent(); + } +} + +void GBCExpanderPass::UpdatePhiInstruction(llvm::BasicBlock* old_basic_block, + llvm::BasicBlock* new_basic_block) { + llvm::TerminatorInst* term_inst = new_basic_block->getTerminator(); + + if (!term_inst) { + return; // No terminating instruction in new_basic_block. Nothing to do. + } + + // Iterate every succeeding basic block + for (unsigned succ_iter = 0, succ_end = term_inst->getNumSuccessors(); + succ_iter != succ_end; ++succ_iter) { + llvm::BasicBlock* succ_basic_block = term_inst->getSuccessor(succ_iter); + + // Iterate every phi instructions in the succeeding basic block + for (llvm::BasicBlock::iterator + inst_iter = succ_basic_block->begin(), + inst_end = succ_basic_block->end(); + inst_iter != inst_end; ++inst_iter) { + llvm::PHINode *phi = llvm::dyn_cast<llvm::PHINode>(inst_iter); + + if (!phi) { + break; // Meet non-phi instruction. Done. + } + + // Update the incoming block of this phi instruction + for (llvm::PHINode::block_iterator + ibb_iter = phi->block_begin(), ibb_end = phi->block_end(); + ibb_iter != ibb_end; ++ibb_iter) { + if (*ibb_iter == old_basic_block) { + *ibb_iter = new_basic_block; + } + } + } + } +} + +llvm::Value* GBCExpanderPass::ExpandToRuntime(runtime_support::RuntimeId rt, + llvm::CallInst& inst) { + // Some GBC intrinsic can directly replace with IBC runtime. "Directly" means + // the arguments passed to the GBC intrinsic are as the same as IBC runtime + // function, therefore only called function is needed to change. + unsigned num_args = inst.getNumArgOperands(); + + if (num_args <= 0) { + return irb_.CreateCall(irb_.GetRuntime(rt)); + } else { + std::vector<llvm::Value*> args; + for (unsigned i = 0; i < num_args; i++) { + args.push_back(inst.getArgOperand(i)); + } + + return irb_.CreateCall(irb_.GetRuntime(rt), args); + } +} + +void +GBCExpanderPass::EmitStackOverflowCheck(llvm::Instruction* first_non_alloca) { + llvm::Function* func = first_non_alloca->getParent()->getParent(); + llvm::Module* module = func->getParent(); + + // Call llvm intrinsic function to get frame address. + llvm::Function* frameaddress = + llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::frameaddress); + + // The type of llvm::frameaddress is: i8* @llvm.frameaddress(i32) + llvm::Value* frame_address = irb_.CreateCall(frameaddress, irb_.getInt32(0)); + + // Cast i8* to int + frame_address = irb_.CreatePtrToInt(frame_address, irb_.getPtrEquivIntTy()); + + // Get thread.stack_end_ + llvm::Value* stack_end = + irb_.Runtime().EmitLoadFromThreadOffset(art::Thread::StackEndOffset().Int32Value(), + irb_.getPtrEquivIntTy(), + kTBAARuntimeInfo); + + // Check the frame address < thread.stack_end_ ? + llvm::Value* is_stack_overflow = irb_.CreateICmpULT(frame_address, stack_end); + + llvm::BasicBlock* block_exception = + llvm::BasicBlock::Create(context_, "stack_overflow", func); + + llvm::BasicBlock* block_continue = + llvm::BasicBlock::Create(context_, "stack_overflow_cont", func); + + irb_.CreateCondBr(is_stack_overflow, block_exception, block_continue, kUnlikely); + + // If stack overflow, throw exception. + irb_.SetInsertPoint(block_exception); + irb_.CreateCall(irb_.GetRuntime(runtime_support::ThrowStackOverflowException)); + + // Unwind. + llvm::Type* ret_type = func->getReturnType(); + if (ret_type->isVoidTy()) { + irb_.CreateRetVoid(); + } else { + // The return value is ignored when there's an exception. MethodCompiler + // returns zero value under the the corresponding return type in this case. + // GBCExpander returns LLVM undef value here for brevity + irb_.CreateRet(llvm::UndefValue::get(ret_type)); + } + + irb_.SetInsertPoint(block_continue); +} + +llvm::Value* GBCExpanderPass::EmitLoadDexCacheAddr(art::MemberOffset offset) { + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + return irb_.LoadFromObjectOffset(method_object_addr, + offset.Int32Value(), + irb_.getJObjectTy(), + kTBAAConstJObject); +} + +llvm::Value* +GBCExpanderPass::EmitLoadDexCacheStaticStorageFieldAddr(uint32_t type_idx) { + llvm::Value* static_storage_dex_cache_addr = + EmitLoadDexCacheAddr(art::mirror::AbstractMethod::DexCacheInitializedStaticStorageOffset()); + + llvm::Value* type_idx_value = irb_.getPtrEquivInt(type_idx); + + return EmitArrayGEP(static_storage_dex_cache_addr, type_idx_value, kObject); +} + +llvm::Value* +GBCExpanderPass::EmitLoadDexCacheResolvedTypeFieldAddr(uint32_t type_idx) { + llvm::Value* resolved_type_dex_cache_addr = + EmitLoadDexCacheAddr(art::mirror::AbstractMethod::DexCacheResolvedTypesOffset()); + + llvm::Value* type_idx_value = irb_.getPtrEquivInt(type_idx); + + return EmitArrayGEP(resolved_type_dex_cache_addr, type_idx_value, kObject); +} + +llvm::Value* GBCExpanderPass:: +EmitLoadDexCacheResolvedMethodFieldAddr(uint32_t method_idx) { + llvm::Value* resolved_method_dex_cache_addr = + EmitLoadDexCacheAddr(art::mirror::AbstractMethod::DexCacheResolvedMethodsOffset()); + + llvm::Value* method_idx_value = irb_.getPtrEquivInt(method_idx); + + return EmitArrayGEP(resolved_method_dex_cache_addr, method_idx_value, kObject); +} + +llvm::Value* GBCExpanderPass:: +EmitLoadDexCacheStringFieldAddr(uint32_t string_idx) { + llvm::Value* string_dex_cache_addr = + EmitLoadDexCacheAddr(art::mirror::AbstractMethod::DexCacheStringsOffset()); + + llvm::Value* string_idx_value = irb_.getPtrEquivInt(string_idx); + + return EmitArrayGEP(string_dex_cache_addr, string_idx_value, kObject); +} + +llvm::Value* GBCExpanderPass::EmitLoadMethodObjectAddr() { + llvm::Function* parent_func = irb_.GetInsertBlock()->getParent(); + return parent_func->arg_begin(); +} + +llvm::Value* GBCExpanderPass::EmitLoadArrayLength(llvm::Value* array) { + // Load array length + return irb_.LoadFromObjectOffset(array, + art::mirror::Array::LengthOffset().Int32Value(), + irb_.getJIntTy(), + kTBAAConstJObject); + +} + +llvm::Value* +GBCExpanderPass::EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx) { + llvm::Value* callee_method_object_field_addr = + EmitLoadDexCacheResolvedMethodFieldAddr(callee_method_idx); + + return irb_.CreateLoad(callee_method_object_field_addr, kTBAARuntimeInfo); +} + +llvm::Value* GBCExpanderPass:: +EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx, llvm::Value* this_addr) { + // Load class object of *this* pointer + llvm::Value* class_object_addr = + irb_.LoadFromObjectOffset(this_addr, + art::mirror::Object::ClassOffset().Int32Value(), + irb_.getJObjectTy(), + kTBAAConstJObject); + + // Load vtable address + llvm::Value* vtable_addr = + irb_.LoadFromObjectOffset(class_object_addr, + art::mirror::Class::VTableOffset().Int32Value(), + irb_.getJObjectTy(), + kTBAAConstJObject); + + // Load callee method object + llvm::Value* vtable_idx_value = + irb_.getPtrEquivInt(static_cast<uint64_t>(vtable_idx)); + + llvm::Value* method_field_addr = + EmitArrayGEP(vtable_addr, vtable_idx_value, kObject); + + return irb_.CreateLoad(method_field_addr, kTBAAConstJObject); +} + +// Emit Array GetElementPtr +llvm::Value* GBCExpanderPass::EmitArrayGEP(llvm::Value* array_addr, + llvm::Value* index_value, + JType elem_jty) { + + int data_offset; + if (elem_jty == kLong || elem_jty == kDouble || + (elem_jty == kObject && sizeof(uint64_t) == sizeof(art::mirror::Object*))) { + data_offset = art::mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); + } else { + data_offset = art::mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); + } + + llvm::Constant* data_offset_value = + irb_.getPtrEquivInt(data_offset); + + llvm::Type* elem_type = irb_.getJType(elem_jty); + + llvm::Value* array_data_addr = + irb_.CreatePtrDisp(array_addr, data_offset_value, + elem_type->getPointerTo()); + + return irb_.CreateGEP(array_data_addr, index_value); +} + +llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + art::InvokeType invoke_type = + static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0))); + bool is_static = (invoke_type == art::kStatic); + art::MethodReference target_method(dex_compilation_unit_->GetDexFile(), + LV2UInt(call_inst.getArgOperand(1))); + + // Load *this* actual parameter + llvm::Value* this_addr = (!is_static) ? call_inst.getArgOperand(3) : NULL; + + // Compute invoke related information for compiler decision + int vtable_idx = -1; + uintptr_t direct_code = 0; + uintptr_t direct_method = 0; + bool is_fast_path = driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, + invoke_type, target_method, + vtable_idx, + direct_code, direct_method, + true); + // Load the method object + llvm::Value* callee_method_object_addr = NULL; + + if (!is_fast_path) { + callee_method_object_addr = + EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index, invoke_type, + this_addr, dex_pc, is_fast_path); + } else { + switch (invoke_type) { + case art::kStatic: + case art::kDirect: + if (direct_method != 0u && + direct_method != static_cast<uintptr_t>(-1)) { + callee_method_object_addr = + irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_method), + irb_.getJObjectTy()); + } else { + callee_method_object_addr = + EmitLoadSDCalleeMethodObjectAddr(target_method.dex_method_index); + } + break; + + case art::kVirtual: + DCHECK(vtable_idx != -1); + callee_method_object_addr = + EmitLoadVirtualCalleeMethodObjectAddr(vtable_idx, this_addr); + break; + + case art::kSuper: + LOG(FATAL) << "invoke-super should be promoted to invoke-direct in " + "the fast path."; + break; + + case art::kInterface: + callee_method_object_addr = + EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index, + invoke_type, this_addr, + dex_pc, is_fast_path); + break; + } + } + + // Load the actual parameter + std::vector<llvm::Value*> args; + + args.push_back(callee_method_object_addr); // method object for callee + + for (uint32_t i = 3; i < call_inst.getNumArgOperands(); ++i) { + args.push_back(call_inst.getArgOperand(i)); + } + + llvm::Value* code_addr; + llvm::Type* func_type = GetFunctionType(call_inst.getType(), + target_method.dex_method_index, is_static); + if (direct_code != 0u && direct_code != static_cast<uintptr_t>(-1)) { + code_addr = + irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_code), + func_type->getPointerTo()); + } else { + code_addr = + irb_.LoadFromObjectOffset(callee_method_object_addr, + art::mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + func_type->getPointerTo(), kTBAARuntimeInfo); + } + + // Invoke callee + EmitUpdateDexPC(dex_pc); + llvm::Value* retval = irb_.CreateCall(code_addr, args); + EmitGuard_ExceptionLandingPad(dex_pc); + + return retval; +} + +bool GBCExpanderPass::EmitIntrinsic(llvm::CallInst& call_inst, + llvm::Value** result) { + DCHECK(result != NULL); + + uint32_t callee_method_idx = LV2UInt(call_inst.getArgOperand(1)); + std::string callee_method_name( + PrettyMethod(callee_method_idx, *dex_compilation_unit_->GetDexFile())); + + if (callee_method_name == "int java.lang.String.length()") { + return EmitIntrinsicStringLengthOrIsEmpty(call_inst, result, + false /* is_empty */); + } + if (callee_method_name == "boolean java.lang.String.isEmpty()") { + return EmitIntrinsicStringLengthOrIsEmpty(call_inst, result, + true /* is_empty */); + } + + *result = NULL; + return false; +} + +bool GBCExpanderPass::EmitIntrinsicStringLengthOrIsEmpty(llvm::CallInst& call_inst, + llvm::Value** result, + bool is_empty) { + art::InvokeType invoke_type = + static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0))); + DCHECK_NE(invoke_type, art::kStatic); + DCHECK_EQ(call_inst.getNumArgOperands(), 4U); + + llvm::Value* this_object = call_inst.getArgOperand(3); + llvm::Value* string_count = + irb_.LoadFromObjectOffset(this_object, + art::mirror::String::CountOffset().Int32Value(), + irb_.getJIntTy(), + kTBAAConstJObject); + if (is_empty) { + llvm::Value* count_equals_zero = irb_.CreateICmpEQ(string_count, + irb_.getJInt(0)); + llvm::Value* is_empty = irb_.CreateSelect(count_equals_zero, + irb_.getJBoolean(true), + irb_.getJBoolean(false)); + is_empty = SignOrZeroExtendCat1Types(is_empty, kBoolean); + *result = is_empty; + } else { + *result = string_count; + } + return true; +} + +void GBCExpanderPass::Expand_TestSuspend(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + + llvm::Value* suspend_count = + irb_.Runtime().EmitLoadFromThreadOffset(art::Thread::ThreadFlagsOffset().Int32Value(), + irb_.getInt16Ty(), + kTBAARuntimeInfo); + llvm::Value* is_suspend = irb_.CreateICmpNE(suspend_count, irb_.getInt16(0)); + + llvm::BasicBlock* basic_block_suspend = CreateBasicBlockWithDexPC(dex_pc, "suspend"); + llvm::BasicBlock* basic_block_cont = CreateBasicBlockWithDexPC(dex_pc, "suspend_cont"); + + irb_.CreateCondBr(is_suspend, basic_block_suspend, basic_block_cont, kUnlikely); + + irb_.SetInsertPoint(basic_block_suspend); + if (dex_pc != art::DexFile::kDexNoIndex) { + EmitUpdateDexPC(dex_pc); + } + irb_.Runtime().EmitTestSuspend(); + + llvm::BasicBlock* basic_block_exception = CreateBasicBlockWithDexPC(dex_pc, "exception"); + llvm::Value* exception_pending = irb_.Runtime().EmitIsExceptionPending(); + irb_.CreateCondBr(exception_pending, basic_block_exception, basic_block_cont, kUnlikely); + + irb_.SetInsertPoint(basic_block_exception); + llvm::Type* ret_type = call_inst.getParent()->getParent()->getReturnType(); + if (ret_type->isVoidTy()) { + irb_.CreateRetVoid(); + } else { + // The return value is ignored when there's an exception. + irb_.CreateRet(llvm::UndefValue::get(ret_type)); + } + + irb_.SetInsertPoint(basic_block_cont); + return; +} + +void GBCExpanderPass::Expand_MarkGCCard(llvm::CallInst& call_inst) { + irb_.Runtime().EmitMarkGCCard(call_inst.getArgOperand(0), call_inst.getArgOperand(1)); + return; +} + +llvm::Value* +GBCExpanderPass::Expand_LoadStringFromDexCache(llvm::Value* string_idx_value) { + uint32_t string_idx = + llvm::cast<llvm::ConstantInt>(string_idx_value)->getZExtValue(); + + llvm::Value* string_field_addr = EmitLoadDexCacheStringFieldAddr(string_idx); + + return irb_.CreateLoad(string_field_addr, kTBAARuntimeInfo); +} + +llvm::Value* +GBCExpanderPass::Expand_LoadTypeFromDexCache(llvm::Value* type_idx_value) { + uint32_t type_idx = + llvm::cast<llvm::ConstantInt>(type_idx_value)->getZExtValue(); + + llvm::Value* type_field_addr = + EmitLoadDexCacheResolvedTypeFieldAddr(type_idx); + + return irb_.CreateLoad(type_field_addr, kTBAARuntimeInfo); +} + +void GBCExpanderPass::Expand_LockObject(llvm::Value* obj) { + rtb_.EmitLockObject(obj); + return; +} + +void GBCExpanderPass::Expand_UnlockObject(llvm::Value* obj) { + rtb_.EmitUnlockObject(obj); + return; +} + +llvm::Value* GBCExpanderPass::Expand_ArrayGet(llvm::Value* array_addr, + llvm::Value* index_value, + JType elem_jty) { + llvm::Value* array_elem_addr = + EmitArrayGEP(array_addr, index_value, elem_jty); + + return irb_.CreateLoad(array_elem_addr, kTBAAHeapArray, elem_jty); +} + +void GBCExpanderPass::Expand_ArrayPut(llvm::Value* new_value, + llvm::Value* array_addr, + llvm::Value* index_value, + JType elem_jty) { + llvm::Value* array_elem_addr = + EmitArrayGEP(array_addr, index_value, elem_jty); + + irb_.CreateStore(new_value, array_elem_addr, kTBAAHeapArray, elem_jty); + + return; +} + +void GBCExpanderPass::Expand_FilledNewArray(llvm::CallInst& call_inst) { + // Most of the codes refer to MethodCompiler::EmitInsn_FilledNewArray + llvm::Value* array = call_inst.getArgOperand(0); + + uint32_t element_jty = + llvm::cast<llvm::ConstantInt>(call_inst.getArgOperand(1))->getZExtValue(); + + DCHECK(call_inst.getNumArgOperands() > 2); + unsigned num_elements = (call_inst.getNumArgOperands() - 2); + + bool is_elem_int_ty = (static_cast<JType>(element_jty) == kInt); + + uint32_t alignment; + llvm::Constant* elem_size; + llvm::PointerType* field_type; + + // NOTE: Currently filled-new-array only supports 'L', '[', and 'I' + // as the element, thus we are only checking 2 cases: primitive int and + // non-primitive type. + if (is_elem_int_ty) { + alignment = sizeof(int32_t); + elem_size = irb_.getPtrEquivInt(sizeof(int32_t)); + field_type = irb_.getJIntTy()->getPointerTo(); + } else { + alignment = irb_.getSizeOfPtrEquivInt(); + elem_size = irb_.getSizeOfPtrEquivIntValue(); + field_type = irb_.getJObjectTy()->getPointerTo(); + } + + llvm::Value* data_field_offset = + irb_.getPtrEquivInt(art::mirror::Array::DataOffset(alignment).Int32Value()); + + llvm::Value* data_field_addr = + irb_.CreatePtrDisp(array, data_field_offset, field_type); + + for (unsigned i = 0; i < num_elements; ++i) { + // Values to fill the array begin at the 3rd argument + llvm::Value* reg_value = call_inst.getArgOperand(2 + i); + + irb_.CreateStore(reg_value, data_field_addr, kTBAAHeapArray); + + data_field_addr = + irb_.CreatePtrDisp(data_field_addr, elem_size, field_type); + } + + return; +} + +llvm::Value* GBCExpanderPass::Expand_IGetFast(llvm::Value* field_offset_value, + llvm::Value* /*is_volatile_value*/, + llvm::Value* object_addr, + JType field_jty) { + int field_offset = + llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue(); + + DCHECK_GE(field_offset, 0); + + llvm::PointerType* field_type = + irb_.getJType(field_jty)->getPointerTo(); + + 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. + return irb_.CreateLoad(field_addr, kTBAAHeapInstance, field_jty); +} + +void GBCExpanderPass::Expand_IPutFast(llvm::Value* field_offset_value, + llvm::Value* /* is_volatile_value */, + llvm::Value* object_addr, + llvm::Value* new_value, + JType field_jty) { + int field_offset = + llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue(); + + DCHECK_GE(field_offset, 0); + + llvm::PointerType* field_type = + irb_.getJType(field_jty)->getPointerTo(); + + 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); + + return; +} + +llvm::Value* GBCExpanderPass::Expand_SGetFast(llvm::Value* static_storage_addr, + llvm::Value* field_offset_value, + llvm::Value* /*is_volatile_value*/, + JType field_jty) { + int field_offset = + llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue(); + + DCHECK_GE(field_offset, 0); + + 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)->getPointerTo()); + + // TODO: Check is_volatile. We need to generate atomic store instruction + // when is_volatile is true. + return irb_.CreateLoad(static_field_addr, kTBAAHeapStatic, field_jty); +} + +void GBCExpanderPass::Expand_SPutFast(llvm::Value* static_storage_addr, + llvm::Value* field_offset_value, + llvm::Value* /* is_volatile_value */, + llvm::Value* new_value, + JType field_jty) { + int field_offset = + llvm::cast<llvm::ConstantInt>(field_offset_value)->getSExtValue(); + + DCHECK_GE(field_offset, 0); + + 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)->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); + + return; +} + +llvm::Value* +GBCExpanderPass::Expand_LoadDeclaringClassSSB(llvm::Value* method_object_addr) { + return irb_.LoadFromObjectOffset(method_object_addr, + art::mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), + irb_.getJObjectTy(), + kTBAAConstJObject); +} + +llvm::Value* +GBCExpanderPass::Expand_LoadClassSSBFromDexCache(llvm::Value* type_idx_value) { + uint32_t type_idx = + llvm::cast<llvm::ConstantInt>(type_idx_value)->getZExtValue(); + + llvm::Value* storage_field_addr = + EmitLoadDexCacheStaticStorageFieldAddr(type_idx); + + return irb_.CreateLoad(storage_field_addr, kTBAARuntimeInfo); +} + +llvm::Value* +GBCExpanderPass::Expand_GetSDCalleeMethodObjAddrFast(llvm::Value* callee_method_idx_value) { + uint32_t callee_method_idx = + llvm::cast<llvm::ConstantInt>(callee_method_idx_value)->getZExtValue(); + + return EmitLoadSDCalleeMethodObjectAddr(callee_method_idx); +} + +llvm::Value* GBCExpanderPass::Expand_GetVirtualCalleeMethodObjAddrFast( + llvm::Value* vtable_idx_value, + llvm::Value* this_addr) { + int vtable_idx = + llvm::cast<llvm::ConstantInt>(vtable_idx_value)->getSExtValue(); + + return EmitLoadVirtualCalleeMethodObjectAddr(vtable_idx, this_addr); +} + +llvm::Value* GBCExpanderPass::Expand_Invoke(llvm::CallInst& call_inst) { + // Most of the codes refer to MethodCompiler::EmitInsn_Invoke + llvm::Value* callee_method_object_addr = call_inst.getArgOperand(0); + unsigned num_args = call_inst.getNumArgOperands(); + llvm::Type* ret_type = call_inst.getType(); + + // Determine the function type of the callee method + std::vector<llvm::Type*> args_type; + std::vector<llvm::Value*> args; + for (unsigned i = 0; i < num_args; i++) { + args.push_back(call_inst.getArgOperand(i)); + args_type.push_back(args[i]->getType()); + } + + llvm::FunctionType* callee_method_type = + llvm::FunctionType::get(ret_type, args_type, false); + + llvm::Value* code_addr = + irb_.LoadFromObjectOffset(callee_method_object_addr, + art::mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + callee_method_type->getPointerTo(), + kTBAARuntimeInfo); + + // Invoke callee + llvm::Value* retval = irb_.CreateCall(code_addr, args); + + return retval; +} + +llvm::Value* GBCExpanderPass::Expand_DivRem(llvm::CallInst& call_inst, + bool is_div, JType op_jty) { + llvm::Value* dividend = call_inst.getArgOperand(0); + llvm::Value* divisor = call_inst.getArgOperand(1); + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + EmitGuard_DivZeroException(dex_pc, divisor, op_jty); + // Most of the codes refer to MethodCompiler::EmitIntDivRemResultComputation + + // Check the special case: MININT / -1 = MININT + // That case will cause overflow, which is undefined behavior in llvm. + // So we check the divisor is -1 or not, if the divisor is -1, we do + // the special path to avoid undefined behavior. + llvm::Type* op_type = irb_.getJType(op_jty); + llvm::Value* zero = irb_.getJZero(op_jty); + llvm::Value* neg_one = llvm::ConstantInt::getSigned(op_type, -1); + + 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); + + llvm::Value* is_equal_neg_one = irb_.CreateICmpEQ(divisor, neg_one); + irb_.CreateCondBr(is_equal_neg_one, eq_neg_one, ne_neg_one, kUnlikely); + + // If divisor == -1 + irb_.SetInsertPoint(eq_neg_one); + llvm::Value* eq_result; + if (is_div) { + // We can just change from "dividend div -1" to "neg dividend". The sub + // don't care the sign/unsigned because of two's complement representation. + // And the behavior is what we want: + // -(2^n) (2^n)-1 + // MININT < k <= MAXINT -> mul k -1 = -k + // MININT == k -> mul k -1 = k + // + // LLVM use sub to represent 'neg' + eq_result = irb_.CreateSub(zero, dividend); + } else { + // Everything modulo -1 will be 0. + eq_result = zero; + } + irb_.CreateBr(neg_one_cont); + + // If divisor != -1, just do the division. + irb_.SetInsertPoint(ne_neg_one); + llvm::Value* ne_result; + if (is_div) { + ne_result = irb_.CreateSDiv(dividend, divisor); + } else { + ne_result = irb_.CreateSRem(dividend, divisor); + } + irb_.CreateBr(neg_one_cont); + + irb_.SetInsertPoint(neg_one_cont); + llvm::PHINode* result = irb_.CreatePHI(op_type, 2); + result->addIncoming(eq_result, eq_neg_one); + result->addIncoming(ne_result, ne_neg_one); + + return result; +} + +void GBCExpanderPass::Expand_AllocaShadowFrame(llvm::Value* num_vregs_value) { + // Most of the codes refer to MethodCompiler::EmitPrologueAllocShadowFrame and + // MethodCompiler::EmitPushShadowFrame + uint16_t num_vregs = + llvm::cast<llvm::ConstantInt>(num_vregs_value)->getZExtValue(); + + llvm::StructType* shadow_frame_type = + irb_.getShadowFrameTy(num_vregs); + + // Create allocas at the start of entry block. + llvm::IRBuilderBase::InsertPoint irb_ip_original = irb_.saveIP(); + llvm::BasicBlock* entry_block = &func_->front(); + irb_.SetInsertPoint(&entry_block->front()); + + shadow_frame_ = irb_.CreateAlloca(shadow_frame_type); + + // Alloca a pointer to old shadow frame + old_shadow_frame_ = + irb_.CreateAlloca(shadow_frame_type->getElementType(0)->getPointerTo()); + + irb_.restoreIP(irb_ip_original); + + // Push the shadow frame + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + llvm::Value* shadow_frame_upcast = + irb_.CreateConstGEP2_32(shadow_frame_, 0, 0); + + llvm::Value* result = rtb_.EmitPushShadowFrame(shadow_frame_upcast, + method_object_addr, + num_vregs); + + irb_.CreateStore(result, old_shadow_frame_, kTBAARegister); + + return; +} + +void GBCExpanderPass::Expand_SetVReg(llvm::Value* entry_idx, + llvm::Value* value) { + unsigned vreg_idx = LV2UInt(entry_idx); + DCHECK_LT(vreg_idx, dex_compilation_unit_->GetCodeItem()->registers_size_); + + llvm::Value* vreg_addr = shadow_frame_vreg_addresses_[vreg_idx]; + if (UNLIKELY(vreg_addr == NULL)) { + DCHECK(shadow_frame_ != NULL); + + llvm::Value* gep_index[] = { + irb_.getInt32(0), // No pointer displacement + irb_.getInt32(1), // VRegs + entry_idx // Pointer field + }; + + // A shadow frame address must dominate every use in the function so we + // place it in the entry block right after the allocas. + llvm::BasicBlock::iterator first_non_alloca = func_->getEntryBlock().begin(); + while (llvm::isa<llvm::AllocaInst>(first_non_alloca)) { + ++first_non_alloca; + } + + llvm::IRBuilderBase::InsertPoint ip = irb_.saveIP(); + irb_.SetInsertPoint(static_cast<llvm::Instruction*>(first_non_alloca)); + vreg_addr = irb_.CreateGEP(shadow_frame_, gep_index); + shadow_frame_vreg_addresses_[vreg_idx] = vreg_addr; + irb_.restoreIP(ip); + } + + irb_.CreateStore(value, + irb_.CreateBitCast(vreg_addr, value->getType()->getPointerTo()), + kTBAAShadowFrame); + return; +} + +void GBCExpanderPass::Expand_PopShadowFrame() { + if (old_shadow_frame_ == NULL) { + return; + } + rtb_.EmitPopShadowFrame(irb_.CreateLoad(old_shadow_frame_, kTBAARegister)); + return; +} + +void GBCExpanderPass::Expand_UpdateDexPC(llvm::Value* dex_pc_value) { + irb_.StoreToObjectOffset(shadow_frame_, + art::ShadowFrame::DexPCOffset(), + dex_pc_value, + kTBAAShadowFrame); + return; +} + +void GBCExpanderPass::InsertStackOverflowCheck(llvm::Function& func) { + // All alloca instructions are generated in the first basic block of the + // function, and there are no alloca instructions after the first non-alloca + // instruction. + + llvm::BasicBlock* first_basic_block = &func.front(); + + // Look for first non-alloca instruction + llvm::BasicBlock::iterator first_non_alloca = first_basic_block->begin(); + while (llvm::isa<llvm::AllocaInst>(first_non_alloca)) { + ++first_non_alloca; + } + + irb_.SetInsertPoint(first_non_alloca); + + // Insert stack overflow check codes before first_non_alloca (i.e., after all + // alloca instructions) + EmitStackOverflowCheck(&*first_non_alloca); + + irb_.Runtime().EmitTestSuspend(); + + llvm::BasicBlock* next_basic_block = irb_.GetInsertBlock(); + if (next_basic_block != first_basic_block) { + // Splice the rest of the instruction to the continuing basic block + next_basic_block->getInstList().splice( + irb_.GetInsertPoint(), first_basic_block->getInstList(), + first_non_alloca, first_basic_block->end()); + + // Rewrite the basic block + RewriteBasicBlock(next_basic_block); + + // Update the phi-instructions in the successor basic block + UpdatePhiInstruction(first_basic_block, irb_.GetInsertBlock()); + } + + // We have changed the basic block + changed_ = true; +} + +// ==== High-level intrinsic expander ========================================== + +llvm::Value* GBCExpanderPass::Expand_FPCompare(llvm::Value* src1_value, + llvm::Value* src2_value, + bool gt_bias) { + llvm::Value* cmp_eq = irb_.CreateFCmpOEQ(src1_value, src2_value); + llvm::Value* cmp_lt; + + if (gt_bias) { + cmp_lt = irb_.CreateFCmpOLT(src1_value, src2_value); + } else { + cmp_lt = irb_.CreateFCmpULT(src1_value, src2_value); + } + + return EmitCompareResultSelection(cmp_eq, cmp_lt); +} + +llvm::Value* GBCExpanderPass::Expand_LongCompare(llvm::Value* src1_value, llvm::Value* src2_value) { + llvm::Value* cmp_eq = irb_.CreateICmpEQ(src1_value, src2_value); + llvm::Value* cmp_lt = irb_.CreateICmpSLT(src1_value, src2_value); + + return EmitCompareResultSelection(cmp_eq, cmp_lt); +} + +llvm::Value* GBCExpanderPass::EmitCompareResultSelection(llvm::Value* cmp_eq, + llvm::Value* cmp_lt) { + + llvm::Constant* zero = irb_.getJInt(0); + llvm::Constant* pos1 = irb_.getJInt(1); + llvm::Constant* neg1 = irb_.getJInt(-1); + + llvm::Value* result_lt = irb_.CreateSelect(cmp_lt, neg1, pos1); + llvm::Value* result_eq = irb_.CreateSelect(cmp_eq, zero, result_lt); + + return result_eq; +} + +llvm::Value* GBCExpanderPass::Expand_IntegerShift(llvm::Value* src1_value, + llvm::Value* src2_value, + IntegerShiftKind kind, + JType op_jty) { + DCHECK(op_jty == kInt || op_jty == kLong); + + // Mask and zero-extend RHS properly + if (op_jty == kInt) { + src2_value = irb_.CreateAnd(src2_value, 0x1f); + } else { + llvm::Value* masked_src2_value = irb_.CreateAnd(src2_value, 0x3f); + src2_value = irb_.CreateZExt(masked_src2_value, irb_.getJLongTy()); + } + + // Create integer shift llvm instruction + switch (kind) { + case kIntegerSHL: + return irb_.CreateShl(src1_value, src2_value); + + case kIntegerSHR: + return irb_.CreateAShr(src1_value, src2_value); + + case kIntegerUSHR: + return irb_.CreateLShr(src1_value, src2_value); + + default: + LOG(FATAL) << "Unknown integer shift kind: " << kind; + return NULL; + } +} + +llvm::Value* GBCExpanderPass::SignOrZeroExtendCat1Types(llvm::Value* value, JType jty) { + switch (jty) { + case kBoolean: + case kChar: + return irb_.CreateZExt(value, irb_.getJType(kInt)); + case kByte: + case kShort: + return irb_.CreateSExt(value, irb_.getJType(kInt)); + case kVoid: + case kInt: + case kLong: + case kFloat: + case kDouble: + case kObject: + return value; // Nothing to do. + default: + LOG(FATAL) << "Unknown java type: " << jty; + return NULL; + } +} + +llvm::Value* GBCExpanderPass::TruncateCat1Types(llvm::Value* value, JType jty) { + switch (jty) { + case kBoolean: + case kChar: + case kByte: + case kShort: + return irb_.CreateTrunc(value, irb_.getJType(jty)); + case kVoid: + case kInt: + case kLong: + case kFloat: + case kDouble: + case kObject: + return value; // Nothing to do. + default: + LOG(FATAL) << "Unknown java type: " << jty; + return NULL; + } +} + +llvm::Value* GBCExpanderPass::Expand_HLArrayGet(llvm::CallInst& call_inst, + JType elem_jty) { + 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); + int opt_flags = LV2UInt(call_inst.getArgOperand(0)); + + EmitGuard_NullPointerException(dex_pc, array_addr, opt_flags); + EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array_addr, index_value, + opt_flags); + + 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); + + return SignOrZeroExtendCat1Types(array_elem_value, elem_jty); +} + + +void GBCExpanderPass::Expand_HLArrayPut(llvm::CallInst& call_inst, + JType elem_jty) { + 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); + int opt_flags = LV2UInt(call_inst.getArgOperand(0)); + + EmitGuard_NullPointerException(dex_pc, array_addr, opt_flags); + EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array_addr, index_value, + opt_flags); + + new_value = TruncateCat1Types(new_value, 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) { + 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)); + int opt_flags = LV2UInt(call_inst.getArgOperand(0)); + + EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags); + + llvm::Value* field_value; + + int field_offset; + bool is_volatile; + bool is_fast_path = driver_->ComputeInstanceFieldInfo( + field_idx, dex_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); + + if (field_jty == kFloat || field_jty == kDouble) { + field_value = irb_.CreateBitCast(field_value, irb_.getJType(field_jty)); + } + } else { + DCHECK_GE(field_offset, 0); + + llvm::PointerType* field_type = + irb_.getJType(field_jty)->getPointerTo(); + + llvm::ConstantInt* field_offset_value = irb_.getPtrEquivInt(field_offset); + + llvm::Value* field_addr = + irb_.CreatePtrDisp(object_addr, field_offset_value, field_type); + + field_value = irb_.CreateLoad(field_addr, kTBAAHeapInstance, field_jty); + field_value = SignOrZeroExtendCat1Types(field_value, field_jty); + + if (is_volatile) { + irb_.CreateMemoryBarrier(art::kLoadLoad); + } + } + + return field_value; +} + +void GBCExpanderPass::Expand_HLIPut(llvm::CallInst& call_inst, + JType field_jty) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + llvm::Value* new_value = call_inst.getArgOperand(1); + llvm::Value* object_addr = call_inst.getArgOperand(2); + uint32_t field_idx = LV2UInt(call_inst.getArgOperand(3)); + int opt_flags = LV2UInt(call_inst.getArgOperand(0)); + + EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags); + + int field_offset; + bool is_volatile; + bool is_fast_path = driver_->ComputeInstanceFieldInfo( + field_idx, dex_compilation_unit_, field_offset, is_volatile, true); + + if (!is_fast_path) { + llvm::Function* runtime_func; + + if (field_jty == kFloat) { + new_value = irb_.CreateBitCast(new_value, irb_.getJType(kInt)); + } else if (field_jty == kDouble) { + new_value = irb_.CreateBitCast(new_value, irb_.getJType(kLong)); + } + + 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); + + if (is_volatile) { + irb_.CreateMemoryBarrier(art::kStoreStore); + } + + llvm::PointerType* field_type = + irb_.getJType(field_jty)->getPointerTo(); + + llvm::Value* field_offset_value = irb_.getPtrEquivInt(field_offset); + + llvm::Value* field_addr = + irb_.CreatePtrDisp(object_addr, field_offset_value, field_type); + + new_value = TruncateCat1Types(new_value, field_jty); + irb_.CreateStore(new_value, field_addr, kTBAAHeapInstance, field_jty); + + if (is_volatile) { + irb_.CreateMemoryBarrier(art::kLoadLoad); + } + + if (field_jty == kObject) { // If put an object, mark the GC card table. + EmitMarkGCCard(new_value, object_addr); + } + } + + return; +} + +llvm::Value* GBCExpanderPass::EmitLoadConstantClass(uint32_t dex_pc, + uint32_t type_idx) { + if (!driver_->CanAccessTypeWithoutChecks(dex_compilation_unit_->GetDexMethodIndex(), + *dex_compilation_unit_->GetDexFile(), type_idx)) { + llvm::Value* type_idx_value = irb_.getInt32(type_idx); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread(); + + llvm::Function* runtime_func = + irb_.GetRuntime(runtime_support::InitializeTypeAndVerifyAccess); + + EmitUpdateDexPC(dex_pc); + + llvm::Value* type_object_addr = + irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr); + + EmitGuard_ExceptionLandingPad(dex_pc); + + return type_object_addr; + + } else { + // Try to load the class (type) object from the test cache. + llvm::Value* type_field_addr = + EmitLoadDexCacheResolvedTypeFieldAddr(type_idx); + + llvm::Value* type_object_addr = irb_.CreateLoad(type_field_addr, kTBAARuntimeInfo); + + if (driver_->CanAssumeTypeIsPresentInDexCache(*dex_compilation_unit_->GetDexFile(), type_idx)) { + return type_object_addr; + } + + llvm::BasicBlock* block_original = irb_.GetInsertBlock(); + + // Test whether class (type) object is in the dex cache or not + llvm::Value* equal_null = + irb_.CreateICmpEQ(type_object_addr, irb_.getJNull()); + + llvm::BasicBlock* block_cont = + CreateBasicBlockWithDexPC(dex_pc, "cont"); + + llvm::BasicBlock* block_load_class = + CreateBasicBlockWithDexPC(dex_pc, "load_class"); + + irb_.CreateCondBr(equal_null, block_load_class, block_cont, kUnlikely); + + // Failback routine to load the class object + irb_.SetInsertPoint(block_load_class); + + llvm::Function* runtime_func = irb_.GetRuntime(runtime_support::InitializeType); + + 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_type_object_addr = + irb_.CreateCall3(runtime_func, type_idx_value, method_object_addr, thread_object_addr); + + EmitGuard_ExceptionLandingPad(dex_pc); + + llvm::BasicBlock* block_after_load_class = 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(type_object_addr, block_original); + phi->addIncoming(loaded_type_object_addr, block_after_load_class); + + return phi; + } +} + +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, kTBAARuntimeInfo); + + 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) { + 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 = driver_->ComputeStaticFieldInfo( + field_idx, dex_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); + + if (field_jty == kFloat || field_jty == kDouble) { + static_field_value = irb_.CreateBitCast(static_field_value, irb_.getJType(field_jty)); + } + } 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, + art::mirror::AbstractMethod::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)->getPointerTo()); + + static_field_value = irb_.CreateLoad(static_field_addr, kTBAAHeapStatic, field_jty); + static_field_value = SignOrZeroExtendCat1Types(static_field_value, field_jty); + + if (is_volatile) { + irb_.CreateMemoryBarrier(art::kLoadLoad); + } + } + + return static_field_value; +} + +void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst, + JType field_jty) { + 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)); + } + + int field_offset; + int ssb_index; + bool is_referrers_class; + bool is_volatile; + + bool is_fast_path = driver_->ComputeStaticFieldInfo( + field_idx, dex_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); + } + + if (field_jty == kFloat) { + new_value = irb_.CreateBitCast(new_value, irb_.getJType(kInt)); + } else if (field_jty == kDouble) { + new_value = irb_.CreateBitCast(new_value, irb_.getJType(kLong)); + } + + 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, + art::mirror::AbstractMethod::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); + } + + if (is_volatile) { + irb_.CreateMemoryBarrier(art::kStoreStore); + } + + 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)->getPointerTo()); + + new_value = TruncateCat1Types(new_value, field_jty); + irb_.CreateStore(new_value, static_field_addr, kTBAAHeapStatic, field_jty); + + if (is_volatile) { + irb_.CreateMemoryBarrier(art::kStoreLoad); + } + + if (field_jty == kObject) { // If put an object, mark the GC card table. + EmitMarkGCCard(new_value, static_storage_addr); + } + } + + return; +} + +llvm::Value* GBCExpanderPass::Expand_ConstString(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + uint32_t string_idx = LV2UInt(call_inst.getArgOperand(0)); + + llvm::Value* string_field_addr = EmitLoadDexCacheStringFieldAddr(string_idx); + + llvm::Value* string_addr = irb_.CreateLoad(string_field_addr, kTBAARuntimeInfo); + + if (!driver_->CanAssumeStringIsPresentInDexCache(*dex_compilation_unit_->GetDexFile(), + string_idx)) { + llvm::BasicBlock* block_str_exist = + CreateBasicBlockWithDexPC(dex_pc, "str_exist"); + + llvm::BasicBlock* block_str_resolve = + CreateBasicBlockWithDexPC(dex_pc, "str_resolve"); + + llvm::BasicBlock* block_cont = + CreateBasicBlockWithDexPC(dex_pc, "str_cont"); + + // Test: Is the string resolved and in the dex cache? + llvm::Value* equal_null = irb_.CreateICmpEQ(string_addr, irb_.getJNull()); + + irb_.CreateCondBr(equal_null, block_str_resolve, block_str_exist, kUnlikely); + + // String is resolved, go to next basic block. + irb_.SetInsertPoint(block_str_exist); + irb_.CreateBr(block_cont); + + // String is not resolved yet, resolve it now. + irb_.SetInsertPoint(block_str_resolve); + + llvm::Function* runtime_func = irb_.GetRuntime(runtime_support::ResolveString); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + llvm::Value* string_idx_value = irb_.getInt32(string_idx); + + EmitUpdateDexPC(dex_pc); + + llvm::Value* result = irb_.CreateCall2(runtime_func, method_object_addr, + string_idx_value); + + EmitGuard_ExceptionLandingPad(dex_pc); + + irb_.CreateBr(block_cont); + + + llvm::BasicBlock* block_pre_cont = irb_.GetInsertBlock(); + + irb_.SetInsertPoint(block_cont); + + llvm::PHINode* phi = irb_.CreatePHI(irb_.getJObjectTy(), 2); + + phi->addIncoming(string_addr, block_str_exist); + phi->addIncoming(result, block_pre_cont); + + string_addr = phi; + } + + return string_addr; +} + +llvm::Value* GBCExpanderPass::Expand_ConstClass(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0)); + + llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, type_idx); + + return type_object_addr; +} + +void GBCExpanderPass::Expand_MonitorEnter(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + llvm::Value* object_addr = call_inst.getArgOperand(1); + int opt_flags = LV2UInt(call_inst.getArgOperand(0)); + + EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags); + + EmitUpdateDexPC(dex_pc); + + irb_.Runtime().EmitLockObject(object_addr); + + return; +} + +void GBCExpanderPass::Expand_MonitorExit(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + llvm::Value* object_addr = call_inst.getArgOperand(1); + int opt_flags = LV2UInt(call_inst.getArgOperand(0)); + + EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags); + + EmitUpdateDexPC(dex_pc); + + irb_.Runtime().EmitUnlockObject(object_addr); + + EmitGuard_ExceptionLandingPad(dex_pc); + + return; +} + +void GBCExpanderPass::Expand_HLCheckCast(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0)); + llvm::Value* object_addr = call_inst.getArgOperand(1); + + llvm::BasicBlock* block_test_class = + CreateBasicBlockWithDexPC(dex_pc, "test_class"); + + llvm::BasicBlock* block_test_sub_class = + CreateBasicBlockWithDexPC(dex_pc, "test_sub_class"); + + llvm::BasicBlock* block_cont = + CreateBasicBlockWithDexPC(dex_pc, "checkcast_cont"); + + // Test: Is the reference equal to null? Act as no-op when it is null. + llvm::Value* equal_null = irb_.CreateICmpEQ(object_addr, irb_.getJNull()); + + irb_.CreateCondBr(equal_null, block_cont, block_test_class, kUnlikely); + + // Test: Is the object instantiated from the given class? + irb_.SetInsertPoint(block_test_class); + llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, type_idx); + DCHECK_EQ(art::mirror::Object::ClassOffset().Int32Value(), 0); + + llvm::PointerType* jobject_ptr_ty = irb_.getJObjectTy(); + + llvm::Value* object_type_field_addr = + irb_.CreateBitCast(object_addr, jobject_ptr_ty->getPointerTo()); + + llvm::Value* object_type_object_addr = + irb_.CreateLoad(object_type_field_addr, kTBAAConstJObject); + + llvm::Value* equal_class = + irb_.CreateICmpEQ(type_object_addr, object_type_object_addr); + + irb_.CreateCondBr(equal_class, block_cont, block_test_sub_class, kLikely); + + // Test: Is the object instantiated from the subclass of the given class? + irb_.SetInsertPoint(block_test_sub_class); + + EmitUpdateDexPC(dex_pc); + + irb_.CreateCall2(irb_.GetRuntime(runtime_support::CheckCast), + type_object_addr, object_type_object_addr); + + EmitGuard_ExceptionLandingPad(dex_pc); + + irb_.CreateBr(block_cont); + + irb_.SetInsertPoint(block_cont); + + return; +} + +llvm::Value* GBCExpanderPass::Expand_InstanceOf(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0)); + llvm::Value* object_addr = call_inst.getArgOperand(1); + + llvm::BasicBlock* block_nullp = + CreateBasicBlockWithDexPC(dex_pc, "nullp"); + + llvm::BasicBlock* block_test_class = + CreateBasicBlockWithDexPC(dex_pc, "test_class"); + + llvm::BasicBlock* block_class_equals = + CreateBasicBlockWithDexPC(dex_pc, "class_eq"); + + llvm::BasicBlock* block_test_sub_class = + CreateBasicBlockWithDexPC(dex_pc, "test_sub_class"); + + llvm::BasicBlock* block_cont = + CreateBasicBlockWithDexPC(dex_pc, "instance_of_cont"); + + // Overview of the following code : + // We check for null, if so, then false, otherwise check for class == . If so + // then true, otherwise do callout slowpath. + // + // Test: Is the reference equal to null? Set 0 when it is null. + llvm::Value* equal_null = irb_.CreateICmpEQ(object_addr, irb_.getJNull()); + + irb_.CreateCondBr(equal_null, block_nullp, block_test_class, kUnlikely); + + irb_.SetInsertPoint(block_nullp); + irb_.CreateBr(block_cont); + + // Test: Is the object instantiated from the given class? + irb_.SetInsertPoint(block_test_class); + llvm::Value* type_object_addr = EmitLoadConstantClass(dex_pc, type_idx); + DCHECK_EQ(art::mirror::Object::ClassOffset().Int32Value(), 0); + + llvm::PointerType* jobject_ptr_ty = irb_.getJObjectTy(); + + llvm::Value* object_type_field_addr = + irb_.CreateBitCast(object_addr, jobject_ptr_ty->getPointerTo()); + + llvm::Value* object_type_object_addr = + irb_.CreateLoad(object_type_field_addr, kTBAAConstJObject); + + llvm::Value* equal_class = + irb_.CreateICmpEQ(type_object_addr, object_type_object_addr); + + irb_.CreateCondBr(equal_class, block_class_equals, block_test_sub_class, kLikely); + + irb_.SetInsertPoint(block_class_equals); + irb_.CreateBr(block_cont); + + // Test: Is the object instantiated from the subclass of the given class? + irb_.SetInsertPoint(block_test_sub_class); + llvm::Value* result = + irb_.CreateCall2(irb_.GetRuntime(runtime_support::IsAssignable), + type_object_addr, object_type_object_addr); + irb_.CreateBr(block_cont); + + irb_.SetInsertPoint(block_cont); + + llvm::PHINode* phi = irb_.CreatePHI(irb_.getJIntTy(), 3); + + phi->addIncoming(irb_.getJInt(0), block_nullp); + phi->addIncoming(irb_.getJInt(1), block_class_equals); + phi->addIncoming(result, block_test_sub_class); + + return phi; +} + +llvm::Value* GBCExpanderPass::Expand_NewInstance(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0)); + + llvm::Function* runtime_func; + if (driver_->CanAccessInstantiableTypeWithoutChecks(dex_compilation_unit_->GetDexMethodIndex(), + *dex_compilation_unit_->GetDexFile(), + type_idx)) { + runtime_func = irb_.GetRuntime(runtime_support::AllocObject); + } else { + runtime_func = irb_.GetRuntime(runtime_support::AllocObjectWithAccessCheck); + } + + llvm::Constant* type_index_value = irb_.getInt32(type_idx); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread(); + + EmitUpdateDexPC(dex_pc); + + llvm::Value* object_addr = + irb_.CreateCall3(runtime_func, type_index_value, method_object_addr, thread_object_addr); + + EmitGuard_ExceptionLandingPad(dex_pc); + + return object_addr; +} + +llvm::Value* GBCExpanderPass::Expand_HLInvoke(llvm::CallInst& call_inst) { + art::InvokeType invoke_type = static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0))); + bool is_static = (invoke_type == art::kStatic); + + if (!is_static) { + // Test: Is *this* parameter equal to null? + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + llvm::Value* this_addr = call_inst.getArgOperand(3); + int opt_flags = LV2UInt(call_inst.getArgOperand(2)); + + EmitGuard_NullPointerException(dex_pc, this_addr, opt_flags); + } + + llvm::Value* result = NULL; + if (EmitIntrinsic(call_inst, &result)) { + return result; + } + + return EmitInvoke(call_inst); +} + +llvm::Value* GBCExpanderPass::Expand_OptArrayLength(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + // Get the array object address + llvm::Value* array_addr = call_inst.getArgOperand(1); + int opt_flags = LV2UInt(call_inst.getArgOperand(0)); + + EmitGuard_NullPointerException(dex_pc, array_addr, opt_flags); + + // Get the array length and store it to the register + return EmitLoadArrayLength(array_addr); +} + +llvm::Value* GBCExpanderPass::Expand_NewArray(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + uint32_t type_idx = LV2UInt(call_inst.getArgOperand(0)); + llvm::Value* length = call_inst.getArgOperand(1); + + return EmitAllocNewArray(dex_pc, length, type_idx, false); +} + +llvm::Value* GBCExpanderPass::Expand_HLFilledNewArray(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + uint32_t type_idx = LV2UInt(call_inst.getArgOperand(1)); + uint32_t length = call_inst.getNumArgOperands() - 3; + + llvm::Value* object_addr = + EmitAllocNewArray(dex_pc, irb_.getInt32(length), type_idx, true); + + if (length > 0) { + // Check for the element type + uint32_t type_desc_len = 0; + const char* type_desc = + dex_compilation_unit_->GetDexFile()->StringByTypeIdx(type_idx, &type_desc_len); + + DCHECK_GE(type_desc_len, 2u); // should be guaranteed by verifier + DCHECK_EQ(type_desc[0], '['); // should be guaranteed by verifier + bool is_elem_int_ty = (type_desc[1] == 'I'); + + uint32_t alignment; + llvm::Constant* elem_size; + llvm::PointerType* field_type; + + // NOTE: Currently filled-new-array only supports 'L', '[', and 'I' + // as the element, thus we are only checking 2 cases: primitive int and + // non-primitive type. + if (is_elem_int_ty) { + alignment = sizeof(int32_t); + elem_size = irb_.getPtrEquivInt(sizeof(int32_t)); + field_type = irb_.getJIntTy()->getPointerTo(); + } else { + alignment = irb_.getSizeOfPtrEquivInt(); + elem_size = irb_.getSizeOfPtrEquivIntValue(); + field_type = irb_.getJObjectTy()->getPointerTo(); + } + + llvm::Value* data_field_offset = + irb_.getPtrEquivInt(art::mirror::Array::DataOffset(alignment).Int32Value()); + + llvm::Value* data_field_addr = + irb_.CreatePtrDisp(object_addr, data_field_offset, field_type); + + // TODO: Tune this code. Currently we are generating one instruction for + // one element which may be very space consuming. Maybe changing to use + // memcpy may help; however, since we can't guarantee that the alloca of + // dalvik register are continuous, we can't perform such optimization yet. + for (uint32_t i = 0; i < length; ++i) { + llvm::Value* reg_value = call_inst.getArgOperand(i+3); + + irb_.CreateStore(reg_value, data_field_addr, kTBAAHeapArray); + + data_field_addr = + irb_.CreatePtrDisp(data_field_addr, elem_size, field_type); + } + } + + return object_addr; +} + +void GBCExpanderPass::Expand_HLFillArrayData(llvm::CallInst& call_inst) { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + int32_t payload_offset = static_cast<int32_t>(dex_pc) + + LV2SInt(call_inst.getArgOperand(0)); + llvm::Value* array_addr = call_inst.getArgOperand(1); + + const art::Instruction::ArrayDataPayload* payload = + reinterpret_cast<const art::Instruction::ArrayDataPayload*>( + dex_compilation_unit_->GetCodeItem()->insns_ + payload_offset); + + if (payload->element_count == 0) { + // When the number of the elements in the payload is zero, we don't have + // to copy any numbers. However, we should check whether the array object + // address is equal to null or not. + EmitGuard_NullPointerException(dex_pc, array_addr, 0); + } else { + // To save the code size, we are going to call the runtime function to + // copy the content from DexFile. + + // NOTE: We will check for the NullPointerException in the runtime. + + llvm::Function* runtime_func = irb_.GetRuntime(runtime_support::FillArrayData); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + EmitUpdateDexPC(dex_pc); + + irb_.CreateCall4(runtime_func, + method_object_addr, irb_.getInt32(dex_pc), + array_addr, irb_.getInt32(payload_offset)); + + EmitGuard_ExceptionLandingPad(dex_pc); + } + + return; +} + +llvm::Value* GBCExpanderPass::EmitAllocNewArray(uint32_t dex_pc, + llvm::Value* array_length_value, + uint32_t type_idx, + bool is_filled_new_array) { + llvm::Function* runtime_func; + + bool skip_access_check = + driver_->CanAccessTypeWithoutChecks(dex_compilation_unit_->GetDexMethodIndex(), + *dex_compilation_unit_->GetDexFile(), type_idx); + + + if (is_filled_new_array) { + runtime_func = skip_access_check ? + irb_.GetRuntime(runtime_support::CheckAndAllocArray) : + irb_.GetRuntime(runtime_support::CheckAndAllocArrayWithAccessCheck); + } else { + runtime_func = skip_access_check ? + irb_.GetRuntime(runtime_support::AllocArray) : + irb_.GetRuntime(runtime_support::AllocArrayWithAccessCheck); + } + + llvm::Constant* type_index_value = irb_.getInt32(type_idx); + + llvm::Value* method_object_addr = EmitLoadMethodObjectAddr(); + + llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread(); + + EmitUpdateDexPC(dex_pc); + + llvm::Value* object_addr = + irb_.CreateCall4(runtime_func, type_index_value, method_object_addr, + array_length_value, thread_object_addr); + + EmitGuard_ExceptionLandingPad(dex_pc); + + return object_addr; +} + +llvm::Value* GBCExpanderPass:: +EmitCallRuntimeForCalleeMethodObjectAddr(uint32_t callee_method_idx, + art::InvokeType invoke_type, + llvm::Value* this_addr, + uint32_t dex_pc, + bool is_fast_path) { + + llvm::Function* runtime_func = NULL; + + switch (invoke_type) { + case art::kStatic: + runtime_func = irb_.GetRuntime(runtime_support::FindStaticMethodWithAccessCheck); + break; + + case art::kDirect: + runtime_func = irb_.GetRuntime(runtime_support::FindDirectMethodWithAccessCheck); + break; + + case art::kVirtual: + runtime_func = irb_.GetRuntime(runtime_support::FindVirtualMethodWithAccessCheck); + break; + + case art::kSuper: + runtime_func = irb_.GetRuntime(runtime_support::FindSuperMethodWithAccessCheck); + break; + + case art::kInterface: + if (is_fast_path) { + runtime_func = irb_.GetRuntime(runtime_support::FindInterfaceMethod); + } else { + runtime_func = irb_.GetRuntime(runtime_support::FindInterfaceMethodWithAccessCheck); + } + break; + } + + llvm::Value* callee_method_idx_value = irb_.getInt32(callee_method_idx); + + if (this_addr == NULL) { + DCHECK_EQ(invoke_type, art::kStatic); + this_addr = irb_.getJNull(); + } + + llvm::Value* caller_method_object_addr = EmitLoadMethodObjectAddr(); + + llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread(); + + EmitUpdateDexPC(dex_pc); + + llvm::Value* callee_method_object_addr = + irb_.CreateCall4(runtime_func, + callee_method_idx_value, + this_addr, + caller_method_object_addr, + thread_object_addr); + + EmitGuard_ExceptionLandingPad(dex_pc); + + return callee_method_object_addr; +} + +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) { + if (shadow_frame_ == NULL) { + return; + } + irb_.StoreToObjectOffset(shadow_frame_, + art::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, + int opt_flags) { + bool ignore_null_check = ((opt_flags & MIR_IGNORE_NULL_CHECK) != 0); + if (ignore_null_check) { + llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc); + if (lpad) { + // There is at least one catch: create a "fake" conditional branch to + // keep the exception edge to the catch block. + landing_pad_phi_mapping_[lpad].push_back( + std::make_pair(current_bb_->getUniquePredecessor(), + irb_.GetInsertBlock())); + + llvm::BasicBlock* block_continue = + CreateBasicBlockWithDexPC(dex_pc, "cont"); + + irb_.CreateCondBr(irb_.getFalse(), lpad, block_continue, kUnlikely); + + irb_.SetInsertPoint(block_continue); + } + } else { + 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, + int opt_flags) { + bool ignore_range_check = ((opt_flags & MIR_IGNORE_RANGE_CHECK) != 0); + if (ignore_range_check) { + llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc); + if (lpad) { + // There is at least one catch: create a "fake" conditional branch to + // keep the exception edge to the catch block. + landing_pad_phi_mapping_[lpad].push_back( + std::make_pair(current_bb_->getUniquePredecessor(), + irb_.GetInsertBlock())); + + llvm::BasicBlock* block_continue = + CreateBasicBlockWithDexPC(dex_pc, "cont"); + + irb_.CreateCondBr(irb_.getFalse(), lpad, block_continue, kUnlikely); + + irb_.SetInsertPoint(block_continue); + } + } else { + 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); + } +} + +llvm::FunctionType* GBCExpanderPass::GetFunctionType(llvm::Type* ret_type, uint32_t method_idx, + bool is_static) { + // Get method signature + art::DexFile::MethodId const& method_id = + dex_compilation_unit_->GetDexFile()->GetMethodId(method_idx); + + uint32_t shorty_size; + const char* shorty = dex_compilation_unit_->GetDexFile()->GetMethodShorty(method_id, &shorty_size); + CHECK_GE(shorty_size, 1u); + + // 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')); // "this" object pointer + } + + for (uint32_t i = 1; i < shorty_size; ++i) { + char shorty_type = art::RemapShorty(shorty[i]); + args_type.push_back(irb_.getJType(shorty_type)); + } + + 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) + art::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 < dex_compilation_unit_->GetCodeItem()->insns_size_in_code_units_); + CHECK(basic_blocks_[dex_pc] != NULL); + return basic_blocks_[dex_pc]; +} + +int32_t GBCExpanderPass::GetTryItemOffset(uint32_t dex_pc) { + int32_t min = 0; + int32_t max = dex_compilation_unit_->GetCodeItem()->tries_size_ - 1; + + while (min <= max) { + int32_t mid = min + (max - min) / 2; + + const art::DexFile::TryItem* ti = + art::DexFile::GetTryItems(*dex_compilation_unit_->GetCodeItem(), 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 art::DexFile::TryItem* ti = art::DexFile::GetTryItems(*dex_compilation_unit_->GetCodeItem(), + ti_offset); + + std::string lpadname; + +#if !defined(NDEBUG) + art::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 + art::CatchHandlerIterator iter(*dex_compilation_unit_->GetCodeItem(), 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 = dex_compilation_unit_->GetShorty()[0]; + ret_shorty = art::RemapShorty(ret_shorty); + 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)) { + landing_pad_phi_mapping_[lpad].push_back(std::make_pair(current_bb_->getUniquePredecessor(), + irb_.GetInsertBlock())); + 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)) { + landing_pad_phi_mapping_[lpad].push_back(std::make_pair(current_bb_->getUniquePredecessor(), + irb_.GetInsertBlock())); + 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) { + switch (intr_id) { + //==- Thread -----------------------------------------------------------==// + case IntrinsicHelper::GetCurrentThread: { + return irb_.Runtime().EmitGetCurrentThread(); + } + case IntrinsicHelper::CheckSuspend: { + Expand_TestSuspend(call_inst); + return NULL; + } + case IntrinsicHelper::TestSuspend: { + Expand_TestSuspend(call_inst); + return NULL; + } + case IntrinsicHelper::MarkGCCard: { + Expand_MarkGCCard(call_inst); + return NULL; + } + + //==- Exception --------------------------------------------------------==// + case IntrinsicHelper::ThrowException: { + return ExpandToRuntime(runtime_support::ThrowException, call_inst); + } + case IntrinsicHelper::HLThrowException: { + uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0)); + + EmitUpdateDexPC(dex_pc); + + irb_.CreateCall(irb_.GetRuntime(runtime_support::ThrowException), + call_inst.getArgOperand(0)); + + EmitGuard_ExceptionLandingPad(dex_pc); + return NULL; + } + case IntrinsicHelper::GetException: { + return irb_.Runtime().EmitGetAndClearException(); + } + case IntrinsicHelper::IsExceptionPending: { + return irb_.Runtime().EmitIsExceptionPending(); + } + case IntrinsicHelper::FindCatchBlock: { + return ExpandToRuntime(runtime_support::FindCatchBlock, call_inst); + } + case IntrinsicHelper::ThrowDivZeroException: { + return ExpandToRuntime(runtime_support::ThrowDivZeroException, call_inst); + } + case IntrinsicHelper::ThrowNullPointerException: { + return ExpandToRuntime(runtime_support::ThrowNullPointerException, call_inst); + } + case IntrinsicHelper::ThrowIndexOutOfBounds: { + return ExpandToRuntime(runtime_support::ThrowIndexOutOfBounds, call_inst); + } + + //==- Const String -----------------------------------------------------==// + case IntrinsicHelper::ConstString: { + return Expand_ConstString(call_inst); + } + case IntrinsicHelper::LoadStringFromDexCache: { + return Expand_LoadStringFromDexCache(call_inst.getArgOperand(0)); + } + case IntrinsicHelper::ResolveString: { + return ExpandToRuntime(runtime_support::ResolveString, call_inst); + } + + //==- Const Class ------------------------------------------------------==// + case IntrinsicHelper::ConstClass: { + return Expand_ConstClass(call_inst); + } + case IntrinsicHelper::InitializeTypeAndVerifyAccess: { + return ExpandToRuntime(runtime_support::InitializeTypeAndVerifyAccess, call_inst); + } + case IntrinsicHelper::LoadTypeFromDexCache: { + return Expand_LoadTypeFromDexCache(call_inst.getArgOperand(0)); + } + case IntrinsicHelper::InitializeType: { + return ExpandToRuntime(runtime_support::InitializeType, call_inst); + } + + //==- Lock -------------------------------------------------------------==// + case IntrinsicHelper::LockObject: { + Expand_LockObject(call_inst.getArgOperand(0)); + return NULL; + } + case IntrinsicHelper::UnlockObject: { + Expand_UnlockObject(call_inst.getArgOperand(0)); + return NULL; + } + + //==- Cast -------------------------------------------------------------==// + case IntrinsicHelper::CheckCast: { + return ExpandToRuntime(runtime_support::CheckCast, call_inst); + } + case IntrinsicHelper::HLCheckCast: { + Expand_HLCheckCast(call_inst); + return NULL; + } + case IntrinsicHelper::IsAssignable: { + return ExpandToRuntime(runtime_support::IsAssignable, call_inst); + } + + //==- Alloc ------------------------------------------------------------==// + case IntrinsicHelper::AllocObject: { + return ExpandToRuntime(runtime_support::AllocObject, call_inst); + } + case IntrinsicHelper::AllocObjectWithAccessCheck: { + return ExpandToRuntime(runtime_support::AllocObjectWithAccessCheck, call_inst); + } + + //==- Instance ---------------------------------------------------------==// + case IntrinsicHelper::NewInstance: { + return Expand_NewInstance(call_inst); + } + case IntrinsicHelper::InstanceOf: { + return Expand_InstanceOf(call_inst); + } + + //==- Array ------------------------------------------------------------==// + case IntrinsicHelper::NewArray: { + return Expand_NewArray(call_inst); + } + case IntrinsicHelper::OptArrayLength: { + return Expand_OptArrayLength(call_inst); + } + case IntrinsicHelper::ArrayLength: { + return EmitLoadArrayLength(call_inst.getArgOperand(0)); + } + case IntrinsicHelper::AllocArray: { + return ExpandToRuntime(runtime_support::AllocArray, call_inst); + } + case IntrinsicHelper::AllocArrayWithAccessCheck: { + return ExpandToRuntime(runtime_support::AllocArrayWithAccessCheck, + call_inst); + } + case IntrinsicHelper::CheckAndAllocArray: { + return ExpandToRuntime(runtime_support::CheckAndAllocArray, call_inst); + } + case IntrinsicHelper::CheckAndAllocArrayWithAccessCheck: { + return ExpandToRuntime(runtime_support::CheckAndAllocArrayWithAccessCheck, + call_inst); + } + case IntrinsicHelper::ArrayGet: { + return Expand_ArrayGet(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kInt); + } + case IntrinsicHelper::ArrayGetWide: { + return Expand_ArrayGet(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kLong); + } + case IntrinsicHelper::ArrayGetObject: { + return Expand_ArrayGet(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kObject); + } + case IntrinsicHelper::ArrayGetBoolean: { + return Expand_ArrayGet(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kBoolean); + } + case IntrinsicHelper::ArrayGetByte: { + return Expand_ArrayGet(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kByte); + } + case IntrinsicHelper::ArrayGetChar: { + return Expand_ArrayGet(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kChar); + } + case IntrinsicHelper::ArrayGetShort: { + return Expand_ArrayGet(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kShort); + } + case IntrinsicHelper::ArrayPut: { + Expand_ArrayPut(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kInt); + return NULL; + } + case IntrinsicHelper::ArrayPutWide: { + Expand_ArrayPut(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kLong); + return NULL; + } + case IntrinsicHelper::ArrayPutObject: { + Expand_ArrayPut(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kObject); + return NULL; + } + case IntrinsicHelper::ArrayPutBoolean: { + Expand_ArrayPut(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kBoolean); + return NULL; + } + case IntrinsicHelper::ArrayPutByte: { + Expand_ArrayPut(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kByte); + return NULL; + } + case IntrinsicHelper::ArrayPutChar: { + Expand_ArrayPut(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kChar); + return NULL; + } + case IntrinsicHelper::ArrayPutShort: { + Expand_ArrayPut(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kShort); + return NULL; + } + case IntrinsicHelper::CheckPutArrayElement: { + return ExpandToRuntime(runtime_support::CheckPutArrayElement, call_inst); + } + case IntrinsicHelper::FilledNewArray: { + Expand_FilledNewArray(call_inst); + return NULL; + } + case IntrinsicHelper::FillArrayData: { + return ExpandToRuntime(runtime_support::FillArrayData, call_inst); + } + case IntrinsicHelper::HLFillArrayData: { + Expand_HLFillArrayData(call_inst); + return NULL; + } + case IntrinsicHelper::HLFilledNewArray: { + return Expand_HLFilledNewArray(call_inst); + } + + //==- Instance Field ---------------------------------------------------==// + case IntrinsicHelper::InstanceFieldGet: + case IntrinsicHelper::InstanceFieldGetBoolean: + case IntrinsicHelper::InstanceFieldGetByte: + case IntrinsicHelper::InstanceFieldGetChar: + case IntrinsicHelper::InstanceFieldGetShort: { + return ExpandToRuntime(runtime_support::Get32Instance, call_inst); + } + case IntrinsicHelper::InstanceFieldGetWide: { + return ExpandToRuntime(runtime_support::Get64Instance, call_inst); + } + case IntrinsicHelper::InstanceFieldGetObject: { + return ExpandToRuntime(runtime_support::GetObjectInstance, call_inst); + } + case IntrinsicHelper::InstanceFieldGetFast: { + return Expand_IGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kInt); + } + case IntrinsicHelper::InstanceFieldGetWideFast: { + return Expand_IGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kLong); + } + case IntrinsicHelper::InstanceFieldGetObjectFast: { + return Expand_IGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kObject); + } + case IntrinsicHelper::InstanceFieldGetBooleanFast: { + return Expand_IGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kBoolean); + } + case IntrinsicHelper::InstanceFieldGetByteFast: { + return Expand_IGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kByte); + } + case IntrinsicHelper::InstanceFieldGetCharFast: { + return Expand_IGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kChar); + } + case IntrinsicHelper::InstanceFieldGetShortFast: { + return Expand_IGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kShort); + } + case IntrinsicHelper::InstanceFieldPut: + case IntrinsicHelper::InstanceFieldPutBoolean: + case IntrinsicHelper::InstanceFieldPutByte: + case IntrinsicHelper::InstanceFieldPutChar: + case IntrinsicHelper::InstanceFieldPutShort: { + return ExpandToRuntime(runtime_support::Set32Instance, call_inst); + } + case IntrinsicHelper::InstanceFieldPutWide: { + return ExpandToRuntime(runtime_support::Set64Instance, call_inst); + } + case IntrinsicHelper::InstanceFieldPutObject: { + return ExpandToRuntime(runtime_support::SetObjectInstance, call_inst); + } + case IntrinsicHelper::InstanceFieldPutFast: { + Expand_IPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kInt); + return NULL; + } + case IntrinsicHelper::InstanceFieldPutWideFast: { + Expand_IPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kLong); + return NULL; + } + case IntrinsicHelper::InstanceFieldPutObjectFast: { + Expand_IPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kObject); + return NULL; + } + case IntrinsicHelper::InstanceFieldPutBooleanFast: { + Expand_IPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kBoolean); + return NULL; + } + case IntrinsicHelper::InstanceFieldPutByteFast: { + Expand_IPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kByte); + return NULL; + } + case IntrinsicHelper::InstanceFieldPutCharFast: { + Expand_IPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kChar); + return NULL; + } + case IntrinsicHelper::InstanceFieldPutShortFast: { + Expand_IPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kShort); + return NULL; + } + + //==- Static Field -----------------------------------------------------==// + case IntrinsicHelper::StaticFieldGet: + case IntrinsicHelper::StaticFieldGetBoolean: + case IntrinsicHelper::StaticFieldGetByte: + case IntrinsicHelper::StaticFieldGetChar: + case IntrinsicHelper::StaticFieldGetShort: { + return ExpandToRuntime(runtime_support::Get32Static, call_inst); + } + case IntrinsicHelper::StaticFieldGetWide: { + return ExpandToRuntime(runtime_support::Get64Static, call_inst); + } + case IntrinsicHelper::StaticFieldGetObject: { + return ExpandToRuntime(runtime_support::GetObjectStatic, call_inst); + } + case IntrinsicHelper::StaticFieldGetFast: { + return Expand_SGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kInt); + } + case IntrinsicHelper::StaticFieldGetWideFast: { + return Expand_SGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kLong); + } + case IntrinsicHelper::StaticFieldGetObjectFast: { + return Expand_SGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kObject); + } + case IntrinsicHelper::StaticFieldGetBooleanFast: { + return Expand_SGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kBoolean); + } + case IntrinsicHelper::StaticFieldGetByteFast: { + return Expand_SGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kByte); + } + case IntrinsicHelper::StaticFieldGetCharFast: { + return Expand_SGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kChar); + } + case IntrinsicHelper::StaticFieldGetShortFast: { + return Expand_SGetFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + kShort); + } + case IntrinsicHelper::StaticFieldPut: + case IntrinsicHelper::StaticFieldPutBoolean: + case IntrinsicHelper::StaticFieldPutByte: + case IntrinsicHelper::StaticFieldPutChar: + case IntrinsicHelper::StaticFieldPutShort: { + return ExpandToRuntime(runtime_support::Set32Static, call_inst); + } + case IntrinsicHelper::StaticFieldPutWide: { + return ExpandToRuntime(runtime_support::Set64Static, call_inst); + } + case IntrinsicHelper::StaticFieldPutObject: { + return ExpandToRuntime(runtime_support::SetObjectStatic, call_inst); + } + case IntrinsicHelper::StaticFieldPutFast: { + Expand_SPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kInt); + return NULL; + } + case IntrinsicHelper::StaticFieldPutWideFast: { + Expand_SPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kLong); + return NULL; + } + case IntrinsicHelper::StaticFieldPutObjectFast: { + Expand_SPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kObject); + return NULL; + } + case IntrinsicHelper::StaticFieldPutBooleanFast: { + Expand_SPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kBoolean); + return NULL; + } + case IntrinsicHelper::StaticFieldPutByteFast: { + Expand_SPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kByte); + return NULL; + } + case IntrinsicHelper::StaticFieldPutCharFast: { + Expand_SPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kChar); + return NULL; + } + case IntrinsicHelper::StaticFieldPutShortFast: { + Expand_SPutFast(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + call_inst.getArgOperand(2), + call_inst.getArgOperand(3), + kShort); + return NULL; + } + case IntrinsicHelper::LoadDeclaringClassSSB: { + return Expand_LoadDeclaringClassSSB(call_inst.getArgOperand(0)); + } + case IntrinsicHelper::LoadClassSSBFromDexCache: { + return Expand_LoadClassSSBFromDexCache(call_inst.getArgOperand(0)); + } + case IntrinsicHelper::InitializeAndLoadClassSSB: { + return ExpandToRuntime(runtime_support::InitializeStaticStorage, call_inst); + } + + //==- High-level Array -------------------------------------------------==// + case IntrinsicHelper::HLArrayGet: { + return Expand_HLArrayGet(call_inst, kInt); + } + case IntrinsicHelper::HLArrayGetBoolean: { + return Expand_HLArrayGet(call_inst, kBoolean); + } + case IntrinsicHelper::HLArrayGetByte: { + return Expand_HLArrayGet(call_inst, kByte); + } + case IntrinsicHelper::HLArrayGetChar: { + return Expand_HLArrayGet(call_inst, kChar); + } + case IntrinsicHelper::HLArrayGetShort: { + return Expand_HLArrayGet(call_inst, kShort); + } + case IntrinsicHelper::HLArrayGetFloat: { + return Expand_HLArrayGet(call_inst, kFloat); + } + case IntrinsicHelper::HLArrayGetWide: { + return Expand_HLArrayGet(call_inst, kLong); + } + case IntrinsicHelper::HLArrayGetDouble: { + return Expand_HLArrayGet(call_inst, kDouble); + } + case IntrinsicHelper::HLArrayGetObject: { + return Expand_HLArrayGet(call_inst, kObject); + } + case IntrinsicHelper::HLArrayPut: { + Expand_HLArrayPut(call_inst, kInt); + return NULL; + } + case IntrinsicHelper::HLArrayPutBoolean: { + Expand_HLArrayPut(call_inst, kBoolean); + return NULL; + } + case IntrinsicHelper::HLArrayPutByte: { + Expand_HLArrayPut(call_inst, kByte); + return NULL; + } + case IntrinsicHelper::HLArrayPutChar: { + Expand_HLArrayPut(call_inst, kChar); + return NULL; + } + case IntrinsicHelper::HLArrayPutShort: { + Expand_HLArrayPut(call_inst, kShort); + return NULL; + } + case IntrinsicHelper::HLArrayPutFloat: { + Expand_HLArrayPut(call_inst, kFloat); + return NULL; + } + case IntrinsicHelper::HLArrayPutWide: { + Expand_HLArrayPut(call_inst, kLong); + return NULL; + } + case IntrinsicHelper::HLArrayPutDouble: { + Expand_HLArrayPut(call_inst, kDouble); + return NULL; + } + case IntrinsicHelper::HLArrayPutObject: { + Expand_HLArrayPut(call_inst, kObject); + return NULL; + } + + //==- High-level Instance ----------------------------------------------==// + case IntrinsicHelper::HLIGet: { + return Expand_HLIGet(call_inst, kInt); + } + case IntrinsicHelper::HLIGetBoolean: { + return Expand_HLIGet(call_inst, kBoolean); + } + case IntrinsicHelper::HLIGetByte: { + return Expand_HLIGet(call_inst, kByte); + } + case IntrinsicHelper::HLIGetChar: { + return Expand_HLIGet(call_inst, kChar); + } + case IntrinsicHelper::HLIGetShort: { + return Expand_HLIGet(call_inst, kShort); + } + case IntrinsicHelper::HLIGetFloat: { + return Expand_HLIGet(call_inst, kFloat); + } + case IntrinsicHelper::HLIGetWide: { + return Expand_HLIGet(call_inst, kLong); + } + case IntrinsicHelper::HLIGetDouble: { + return Expand_HLIGet(call_inst, kDouble); + } + case IntrinsicHelper::HLIGetObject: { + return Expand_HLIGet(call_inst, kObject); + } + case IntrinsicHelper::HLIPut: { + Expand_HLIPut(call_inst, kInt); + return NULL; + } + case IntrinsicHelper::HLIPutBoolean: { + Expand_HLIPut(call_inst, kBoolean); + return NULL; + } + case IntrinsicHelper::HLIPutByte: { + Expand_HLIPut(call_inst, kByte); + return NULL; + } + case IntrinsicHelper::HLIPutChar: { + Expand_HLIPut(call_inst, kChar); + return NULL; + } + case IntrinsicHelper::HLIPutShort: { + Expand_HLIPut(call_inst, kShort); + return NULL; + } + case IntrinsicHelper::HLIPutFloat: { + Expand_HLIPut(call_inst, kFloat); + return NULL; + } + case IntrinsicHelper::HLIPutWide: { + Expand_HLIPut(call_inst, kLong); + return NULL; + } + case IntrinsicHelper::HLIPutDouble: { + Expand_HLIPut(call_inst, kDouble); + return NULL; + } + case IntrinsicHelper::HLIPutObject: { + Expand_HLIPut(call_inst, kObject); + return NULL; + } + + //==- High-level Invoke ------------------------------------------------==// + case IntrinsicHelper::HLInvokeVoid: + case IntrinsicHelper::HLInvokeObj: + case IntrinsicHelper::HLInvokeInt: + case IntrinsicHelper::HLInvokeFloat: + case IntrinsicHelper::HLInvokeLong: + case IntrinsicHelper::HLInvokeDouble: { + return Expand_HLInvoke(call_inst); + } + + //==- Invoke -----------------------------------------------------------==// + case IntrinsicHelper::FindStaticMethodWithAccessCheck: { + return ExpandToRuntime(runtime_support::FindStaticMethodWithAccessCheck, call_inst); + } + case IntrinsicHelper::FindDirectMethodWithAccessCheck: { + return ExpandToRuntime(runtime_support::FindDirectMethodWithAccessCheck, call_inst); + } + case IntrinsicHelper::FindVirtualMethodWithAccessCheck: { + return ExpandToRuntime(runtime_support::FindVirtualMethodWithAccessCheck, call_inst); + } + case IntrinsicHelper::FindSuperMethodWithAccessCheck: { + return ExpandToRuntime(runtime_support::FindSuperMethodWithAccessCheck, call_inst); + } + case IntrinsicHelper::FindInterfaceMethodWithAccessCheck: { + return ExpandToRuntime(runtime_support::FindInterfaceMethodWithAccessCheck, call_inst); + } + case IntrinsicHelper::GetSDCalleeMethodObjAddrFast: { + return Expand_GetSDCalleeMethodObjAddrFast(call_inst.getArgOperand(0)); + } + case IntrinsicHelper::GetVirtualCalleeMethodObjAddrFast: { + return Expand_GetVirtualCalleeMethodObjAddrFast( + call_inst.getArgOperand(0), call_inst.getArgOperand(1)); + } + case IntrinsicHelper::GetInterfaceCalleeMethodObjAddrFast: { + return ExpandToRuntime(runtime_support::FindInterfaceMethod, call_inst); + } + case IntrinsicHelper::InvokeRetVoid: + case IntrinsicHelper::InvokeRetBoolean: + case IntrinsicHelper::InvokeRetByte: + case IntrinsicHelper::InvokeRetChar: + case IntrinsicHelper::InvokeRetShort: + case IntrinsicHelper::InvokeRetInt: + case IntrinsicHelper::InvokeRetLong: + case IntrinsicHelper::InvokeRetFloat: + case IntrinsicHelper::InvokeRetDouble: + case IntrinsicHelper::InvokeRetObject: { + return Expand_Invoke(call_inst); + } + + //==- Math -------------------------------------------------------------==// + case IntrinsicHelper::DivInt: { + return Expand_DivRem(call_inst, /* is_div */true, kInt); + } + case IntrinsicHelper::RemInt: { + return Expand_DivRem(call_inst, /* is_div */false, kInt); + } + case IntrinsicHelper::DivLong: { + return Expand_DivRem(call_inst, /* is_div */true, kLong); + } + case IntrinsicHelper::RemLong: { + return Expand_DivRem(call_inst, /* is_div */false, kLong); + } + case IntrinsicHelper::D2L: { + return ExpandToRuntime(runtime_support::art_d2l, call_inst); + } + case IntrinsicHelper::D2I: { + return ExpandToRuntime(runtime_support::art_d2i, call_inst); + } + case IntrinsicHelper::F2L: { + return ExpandToRuntime(runtime_support::art_f2l, call_inst); + } + case IntrinsicHelper::F2I: { + return ExpandToRuntime(runtime_support::art_f2i, call_inst); + } + + //==- High-level Static ------------------------------------------------==// + case IntrinsicHelper::HLSget: { + return Expand_HLSget(call_inst, kInt); + } + case IntrinsicHelper::HLSgetBoolean: { + return Expand_HLSget(call_inst, kBoolean); + } + case IntrinsicHelper::HLSgetByte: { + return Expand_HLSget(call_inst, kByte); + } + case IntrinsicHelper::HLSgetChar: { + return Expand_HLSget(call_inst, kChar); + } + case IntrinsicHelper::HLSgetShort: { + return Expand_HLSget(call_inst, kShort); + } + case IntrinsicHelper::HLSgetFloat: { + return Expand_HLSget(call_inst, kFloat); + } + case IntrinsicHelper::HLSgetWide: { + return Expand_HLSget(call_inst, kLong); + } + case IntrinsicHelper::HLSgetDouble: { + return Expand_HLSget(call_inst, kDouble); + } + case IntrinsicHelper::HLSgetObject: { + return Expand_HLSget(call_inst, kObject); + } + case IntrinsicHelper::HLSput: { + Expand_HLSput(call_inst, kInt); + return NULL; + } + case IntrinsicHelper::HLSputBoolean: { + Expand_HLSput(call_inst, kBoolean); + return NULL; + } + case IntrinsicHelper::HLSputByte: { + Expand_HLSput(call_inst, kByte); + return NULL; + } + case IntrinsicHelper::HLSputChar: { + Expand_HLSput(call_inst, kChar); + return NULL; + } + case IntrinsicHelper::HLSputShort: { + Expand_HLSput(call_inst, kShort); + return NULL; + } + case IntrinsicHelper::HLSputFloat: { + Expand_HLSput(call_inst, kFloat); + return NULL; + } + case IntrinsicHelper::HLSputWide: { + Expand_HLSput(call_inst, kLong); + return NULL; + } + case IntrinsicHelper::HLSputDouble: { + Expand_HLSput(call_inst, kDouble); + return NULL; + } + case IntrinsicHelper::HLSputObject: { + Expand_HLSput(call_inst, kObject); + return NULL; + } + + //==- High-level Monitor -----------------------------------------------==// + case IntrinsicHelper::MonitorEnter: { + Expand_MonitorEnter(call_inst); + return NULL; + } + case IntrinsicHelper::MonitorExit: { + Expand_MonitorExit(call_inst); + return NULL; + } + + //==- Shadow Frame -----------------------------------------------------==// + case IntrinsicHelper::AllocaShadowFrame: { + Expand_AllocaShadowFrame(call_inst.getArgOperand(0)); + return NULL; + } + case IntrinsicHelper::SetVReg: { + Expand_SetVReg(call_inst.getArgOperand(0), + call_inst.getArgOperand(1)); + return NULL; + } + case IntrinsicHelper::PopShadowFrame: { + Expand_PopShadowFrame(); + return NULL; + } + case IntrinsicHelper::UpdateDexPC: { + Expand_UpdateDexPC(call_inst.getArgOperand(0)); + return NULL; + } + + //==- Comparison -------------------------------------------------------==// + case IntrinsicHelper::CmplFloat: + case IntrinsicHelper::CmplDouble: { + return Expand_FPCompare(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + false); + } + case IntrinsicHelper::CmpgFloat: + case IntrinsicHelper::CmpgDouble: { + return Expand_FPCompare(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + true); + } + case IntrinsicHelper::CmpLong: { + return Expand_LongCompare(call_inst.getArgOperand(0), + call_inst.getArgOperand(1)); + } + + //==- Const ------------------------------------------------------------==// + case IntrinsicHelper::ConstInt: + case IntrinsicHelper::ConstLong: { + return call_inst.getArgOperand(0); + } + case IntrinsicHelper::ConstFloat: { + return irb_.CreateBitCast(call_inst.getArgOperand(0), + irb_.getJFloatTy()); + } + case IntrinsicHelper::ConstDouble: { + return irb_.CreateBitCast(call_inst.getArgOperand(0), + irb_.getJDoubleTy()); + } + case IntrinsicHelper::ConstObj: { + CHECK(LV2UInt(call_inst.getArgOperand(0)) == 0); + return irb_.getJNull(); + } + + //==- Method Info ------------------------------------------------------==// + case IntrinsicHelper::MethodInfo: { + // Nothing to be done, because MethodInfo carries optional hints that are + // not needed by the portable path. + return NULL; + } + + //==- Copy -------------------------------------------------------------==// + case IntrinsicHelper::CopyInt: + case IntrinsicHelper::CopyFloat: + case IntrinsicHelper::CopyLong: + case IntrinsicHelper::CopyDouble: + case IntrinsicHelper::CopyObj: { + return call_inst.getArgOperand(0); + } + + //==- Shift ------------------------------------------------------------==// + case IntrinsicHelper::SHLLong: { + return Expand_IntegerShift(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kIntegerSHL, kLong); + } + case IntrinsicHelper::SHRLong: { + return Expand_IntegerShift(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kIntegerSHR, kLong); + } + case IntrinsicHelper::USHRLong: { + return Expand_IntegerShift(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kIntegerUSHR, kLong); + } + case IntrinsicHelper::SHLInt: { + return Expand_IntegerShift(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kIntegerSHL, kInt); + } + case IntrinsicHelper::SHRInt: { + return Expand_IntegerShift(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kIntegerSHR, kInt); + } + case IntrinsicHelper::USHRInt: { + return Expand_IntegerShift(call_inst.getArgOperand(0), + call_inst.getArgOperand(1), + kIntegerUSHR, kInt); + } + + //==- Conversion -------------------------------------------------------==// + case IntrinsicHelper::IntToChar: { + return irb_.CreateZExt(irb_.CreateTrunc(call_inst.getArgOperand(0), irb_.getJCharTy()), + irb_.getJIntTy()); + } + case IntrinsicHelper::IntToShort: { + return irb_.CreateSExt(irb_.CreateTrunc(call_inst.getArgOperand(0), irb_.getJShortTy()), + irb_.getJIntTy()); + } + case IntrinsicHelper::IntToByte: { + return irb_.CreateSExt(irb_.CreateTrunc(call_inst.getArgOperand(0), irb_.getJByteTy()), + irb_.getJIntTy()); + } + + //==- Exception --------------------------------------------------------==// + case IntrinsicHelper::CatchTargets: { + UpdatePhiInstruction(current_bb_, irb_.GetInsertBlock()); + llvm::SwitchInst* si = llvm::dyn_cast<llvm::SwitchInst>(call_inst.getNextNode()); + CHECK(si != NULL); + irb_.CreateBr(si->getDefaultDest()); + si->eraseFromParent(); + return call_inst.getArgOperand(0); + } + + //==- Constructor barrier-----------------------------------------------==// + case IntrinsicHelper::ConstructorBarrier: { + irb_.CreateMemoryBarrier(art::kStoreStore); + return NULL; + } + + //==- Unknown Cases ----------------------------------------------------==// + case IntrinsicHelper::MaxIntrinsicId: + case IntrinsicHelper::UnknownId: + //default: + // NOTE: "default" is intentionally commented so that C/C++ compiler will + // give some warning on unmatched cases. + // NOTE: We should not implement these cases. + break; + } + UNIMPLEMENTED(FATAL) << "Unexpected GBC intrinsic: " << static_cast<int>(intr_id); + return NULL; +} + +} // anonymous namespace + +namespace art { +namespace llvm { + +::llvm::FunctionPass* +CreateGBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb, + CompilerDriver* driver, const DexCompilationUnit* dex_compilation_unit) { + return new GBCExpanderPass(intrinsic_helper, irb, driver, dex_compilation_unit); +} + +} // namespace llvm +} // namespace art diff --git a/compiler/llvm/generated/art_module.cc b/compiler/llvm/generated/art_module.cc new file mode 100644 index 0000000000..bcd90b96a1 --- /dev/null +++ b/compiler/llvm/generated/art_module.cc @@ -0,0 +1,1096 @@ +// Generated with ./gen_art_module_cc.sh + + +#pragma GCC diagnostic ignored "-Wframe-larger-than=" +// TODO: Remove this pragma after llc can generate makeLLVMModuleContents() +// with smaller frame size. + +#include <llvm/IR/DerivedTypes.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Type.h> + +#include <vector> + +using namespace llvm; + +namespace art { +namespace llvm { + + +// Generated by llvm2cpp - DO NOT MODIFY! + + +Module* makeLLVMModuleContents(Module *mod) { + +mod->setModuleIdentifier("art_module.ll"); + +// Type Definitions +std::vector<Type*>FuncTy_0_args; +StructType *StructTy_JavaObject = mod->getTypeByName("JavaObject"); +if (!StructTy_JavaObject) { +StructTy_JavaObject = StructType::create(mod->getContext(), "JavaObject"); +} +std::vector<Type*>StructTy_JavaObject_fields; +if (StructTy_JavaObject->isOpaque()) { +StructTy_JavaObject->setBody(StructTy_JavaObject_fields, /*isPacked=*/false); +} + +PointerType* PointerTy_1 = PointerType::get(StructTy_JavaObject, 0); + +FuncTy_0_args.push_back(PointerTy_1); +StructType *StructTy_ShadowFrame = mod->getTypeByName("ShadowFrame"); +if (!StructTy_ShadowFrame) { +StructTy_ShadowFrame = StructType::create(mod->getContext(), "ShadowFrame"); +} +std::vector<Type*>StructTy_ShadowFrame_fields; +StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32)); +PointerType* PointerTy_2 = PointerType::get(StructTy_ShadowFrame, 0); + +StructTy_ShadowFrame_fields.push_back(PointerTy_2); +StructTy_ShadowFrame_fields.push_back(PointerTy_1); +StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32)); +if (StructTy_ShadowFrame->isOpaque()) { +StructTy_ShadowFrame->setBody(StructTy_ShadowFrame_fields, /*isPacked=*/false); +} + + +FuncTy_0_args.push_back(PointerTy_2); +FunctionType* FuncTy_0 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_0_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_3_args; +FunctionType* FuncTy_3 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_3_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_4_args; +FuncTy_4_args.push_back(PointerTy_1); +FunctionType* FuncTy_4 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_4_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_5_args; +FuncTy_5_args.push_back(PointerTy_1); +FuncTy_5_args.push_back(PointerTy_1); +FunctionType* FuncTy_5 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_5_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_6_args; +FuncTy_6_args.push_back(PointerTy_1); +FunctionType* FuncTy_6 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_6_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_7_args; +FuncTy_7_args.push_back(PointerTy_1); +FuncTy_7_args.push_back(PointerTy_2); +FuncTy_7_args.push_back(PointerTy_1); +FuncTy_7_args.push_back(IntegerType::get(mod->getContext(), 32)); +FunctionType* FuncTy_7 = FunctionType::get( + /*Result=*/PointerTy_2, + /*Params=*/FuncTy_7_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_8_args; +FuncTy_8_args.push_back(PointerTy_2); +FunctionType* FuncTy_8 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_8_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_9_args; +FunctionType* FuncTy_9 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_9_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_10_args; +FuncTy_10_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_10_args.push_back(IntegerType::get(mod->getContext(), 32)); +FunctionType* FuncTy_10 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_10_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_11_args; +FuncTy_11_args.push_back(IntegerType::get(mod->getContext(), 32)); +FunctionType* FuncTy_11 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_11_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_12_args; +FuncTy_12_args.push_back(PointerTy_1); +FuncTy_12_args.push_back(IntegerType::get(mod->getContext(), 32)); +FunctionType* FuncTy_12 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_12_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_13_args; +FuncTy_13_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_13_args.push_back(PointerTy_1); +FuncTy_13_args.push_back(PointerTy_1); +FunctionType* FuncTy_13 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_13_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_14_args; +FuncTy_14_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_14_args.push_back(PointerTy_1); +FuncTy_14_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_14_args.push_back(PointerTy_1); +FunctionType* FuncTy_14 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_14_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_15_args; +FuncTy_15_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_15_args.push_back(PointerTy_1); +FunctionType* FuncTy_15 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_15_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_16_args; +FuncTy_16_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_16_args.push_back(PointerTy_1); +FuncTy_16_args.push_back(PointerTy_1); +FuncTy_16_args.push_back(PointerTy_1); +FunctionType* FuncTy_16 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_16_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_17_args; +FuncTy_17_args.push_back(PointerTy_1); +FuncTy_17_args.push_back(IntegerType::get(mod->getContext(), 32)); +FunctionType* FuncTy_17 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_17_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_18_args; +FuncTy_18_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_18_args.push_back(PointerTy_1); +FuncTy_18_args.push_back(IntegerType::get(mod->getContext(), 32)); +FunctionType* FuncTy_18 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_18_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_19_args; +FuncTy_19_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_19_args.push_back(PointerTy_1); +FuncTy_19_args.push_back(IntegerType::get(mod->getContext(), 64)); +FunctionType* FuncTy_19 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_19_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_20_args; +FuncTy_20_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_20_args.push_back(PointerTy_1); +FuncTy_20_args.push_back(PointerTy_1); +FunctionType* FuncTy_20 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_20_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_21_args; +FuncTy_21_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_21_args.push_back(PointerTy_1); +FunctionType* FuncTy_21 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_21_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_22_args; +FuncTy_22_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_22_args.push_back(PointerTy_1); +FunctionType* FuncTy_22 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 64), + /*Params=*/FuncTy_22_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_23_args; +FuncTy_23_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_23_args.push_back(PointerTy_1); +FunctionType* FuncTy_23 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_23_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_24_args; +FuncTy_24_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_24_args.push_back(PointerTy_1); +FuncTy_24_args.push_back(PointerTy_1); +FuncTy_24_args.push_back(IntegerType::get(mod->getContext(), 32)); +FunctionType* FuncTy_24 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_24_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_25_args; +FuncTy_25_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_25_args.push_back(PointerTy_1); +FuncTy_25_args.push_back(PointerTy_1); +FuncTy_25_args.push_back(IntegerType::get(mod->getContext(), 64)); +FunctionType* FuncTy_25 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_25_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_26_args; +FuncTy_26_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_26_args.push_back(PointerTy_1); +FuncTy_26_args.push_back(PointerTy_1); +FuncTy_26_args.push_back(PointerTy_1); +FunctionType* FuncTy_26 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_26_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_27_args; +FuncTy_27_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_27_args.push_back(PointerTy_1); +FuncTy_27_args.push_back(PointerTy_1); +FunctionType* FuncTy_27 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 64), + /*Params=*/FuncTy_27_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_28_args; +FuncTy_28_args.push_back(PointerTy_1); +FuncTy_28_args.push_back(PointerTy_1); +FunctionType* FuncTy_28 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_28_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_29_args; +FuncTy_29_args.push_back(PointerTy_1); +FuncTy_29_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_29_args.push_back(PointerTy_1); +FuncTy_29_args.push_back(IntegerType::get(mod->getContext(), 32)); +FunctionType* FuncTy_29 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_29_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_30_args; +FuncTy_30_args.push_back(PointerTy_1); +FuncTy_30_args.push_back(PointerTy_1); +FunctionType* FuncTy_30 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_30_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_31_args; +FuncTy_31_args.push_back(Type::getDoubleTy(mod->getContext())); +FunctionType* FuncTy_31 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 64), + /*Params=*/FuncTy_31_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_32_args; +FuncTy_32_args.push_back(Type::getDoubleTy(mod->getContext())); +FunctionType* FuncTy_32 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_32_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_33_args; +FuncTy_33_args.push_back(Type::getFloatTy(mod->getContext())); +FunctionType* FuncTy_33 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 64), + /*Params=*/FuncTy_33_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_34_args; +FuncTy_34_args.push_back(Type::getFloatTy(mod->getContext())); +FunctionType* FuncTy_34 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_34_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_35_args; +FuncTy_35_args.push_back(PointerTy_1); +FunctionType* FuncTy_35 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 32), + /*Params=*/FuncTy_35_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_36_args; +FuncTy_36_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_36_args.push_back(PointerTy_1); +FuncTy_36_args.push_back(PointerTy_1); +FunctionType* FuncTy_36 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_36_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_37_args; +FuncTy_37_args.push_back(PointerTy_1); +FuncTy_37_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_37_args.push_back(PointerTy_1); +FunctionType* FuncTy_37 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_37_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_38_args; +FuncTy_38_args.push_back(PointerTy_1); +FuncTy_38_args.push_back(IntegerType::get(mod->getContext(), 32)); +FuncTy_38_args.push_back(PointerTy_1); +FuncTy_38_args.push_back(PointerTy_1); +FunctionType* FuncTy_38 = FunctionType::get( + /*Result=*/PointerTy_1, + /*Params=*/FuncTy_38_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_39_args; +FunctionType* FuncTy_39 = FunctionType::get( + /*Result=*/IntegerType::get(mod->getContext(), 1), + /*Params=*/FuncTy_39_args, + /*isVarArg=*/false); + +std::vector<Type*>FuncTy_40_args; +FuncTy_40_args.push_back(PointerTy_1); +FunctionType* FuncTy_40 = FunctionType::get( + /*Result=*/Type::getVoidTy(mod->getContext()), + /*Params=*/FuncTy_40_args, + /*isVarArg=*/true); + + +// Function Declarations + +Function* func___art_type_list = mod->getFunction("__art_type_list"); +if (!func___art_type_list) { +func___art_type_list = Function::Create( + /*Type=*/FuncTy_0, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"__art_type_list", mod); // (external, no body) +func___art_type_list->setCallingConv(CallingConv::C); +} +AttributeSet func___art_type_list_PAL; +func___art_type_list->setAttributes(func___art_type_list_PAL); + +Function* func_art_portable_get_current_thread_from_code = mod->getFunction("art_portable_get_current_thread_from_code"); +if (!func_art_portable_get_current_thread_from_code) { +func_art_portable_get_current_thread_from_code = Function::Create( + /*Type=*/FuncTy_3, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_get_current_thread_from_code", mod); // (external, no body) +func_art_portable_get_current_thread_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_get_current_thread_from_code_PAL; +func_art_portable_get_current_thread_from_code->setAttributes(func_art_portable_get_current_thread_from_code_PAL); + +Function* func_art_portable_set_current_thread_from_code = mod->getFunction("art_portable_set_current_thread_from_code"); +if (!func_art_portable_set_current_thread_from_code) { +func_art_portable_set_current_thread_from_code = Function::Create( + /*Type=*/FuncTy_4, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_set_current_thread_from_code", mod); // (external, no body) +func_art_portable_set_current_thread_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_set_current_thread_from_code_PAL; +func_art_portable_set_current_thread_from_code->setAttributes(func_art_portable_set_current_thread_from_code_PAL); + +Function* func_art_portable_lock_object_from_code = mod->getFunction("art_portable_lock_object_from_code"); +if (!func_art_portable_lock_object_from_code) { +func_art_portable_lock_object_from_code = Function::Create( + /*Type=*/FuncTy_5, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_lock_object_from_code", mod); // (external, no body) +func_art_portable_lock_object_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_lock_object_from_code_PAL; +func_art_portable_lock_object_from_code->setAttributes(func_art_portable_lock_object_from_code_PAL); + +Function* func_art_portable_unlock_object_from_code = mod->getFunction("art_portable_unlock_object_from_code"); +if (!func_art_portable_unlock_object_from_code) { +func_art_portable_unlock_object_from_code = Function::Create( + /*Type=*/FuncTy_5, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_unlock_object_from_code", mod); // (external, no body) +func_art_portable_unlock_object_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_unlock_object_from_code_PAL; +func_art_portable_unlock_object_from_code->setAttributes(func_art_portable_unlock_object_from_code_PAL); + +Function* func_art_portable_test_suspend_from_code = mod->getFunction("art_portable_test_suspend_from_code"); +if (!func_art_portable_test_suspend_from_code) { +func_art_portable_test_suspend_from_code = Function::Create( + /*Type=*/FuncTy_6, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_test_suspend_from_code", mod); // (external, no body) +func_art_portable_test_suspend_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_test_suspend_from_code_PAL; +func_art_portable_test_suspend_from_code->setAttributes(func_art_portable_test_suspend_from_code_PAL); + +Function* func_art_portable_push_shadow_frame_from_code = mod->getFunction("art_portable_push_shadow_frame_from_code"); +if (!func_art_portable_push_shadow_frame_from_code) { +func_art_portable_push_shadow_frame_from_code = Function::Create( + /*Type=*/FuncTy_7, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_push_shadow_frame_from_code", mod); // (external, no body) +func_art_portable_push_shadow_frame_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_push_shadow_frame_from_code_PAL; +func_art_portable_push_shadow_frame_from_code->setAttributes(func_art_portable_push_shadow_frame_from_code_PAL); + +Function* func_art_portable_pop_shadow_frame_from_code = mod->getFunction("art_portable_pop_shadow_frame_from_code"); +if (!func_art_portable_pop_shadow_frame_from_code) { +func_art_portable_pop_shadow_frame_from_code = Function::Create( + /*Type=*/FuncTy_8, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_pop_shadow_frame_from_code", mod); // (external, no body) +func_art_portable_pop_shadow_frame_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_pop_shadow_frame_from_code_PAL; +func_art_portable_pop_shadow_frame_from_code->setAttributes(func_art_portable_pop_shadow_frame_from_code_PAL); + +Function* func_art_portable_get_and_clear_exception = mod->getFunction("art_portable_get_and_clear_exception"); +if (!func_art_portable_get_and_clear_exception) { +func_art_portable_get_and_clear_exception = Function::Create( + /*Type=*/FuncTy_4, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_get_and_clear_exception", mod); // (external, no body) +func_art_portable_get_and_clear_exception->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_get_and_clear_exception_PAL; +func_art_portable_get_and_clear_exception->setAttributes(func_art_portable_get_and_clear_exception_PAL); + +Function* func_art_portable_throw_div_zero_from_code = mod->getFunction("art_portable_throw_div_zero_from_code"); +if (!func_art_portable_throw_div_zero_from_code) { +func_art_portable_throw_div_zero_from_code = Function::Create( + /*Type=*/FuncTy_9, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_throw_div_zero_from_code", mod); // (external, no body) +func_art_portable_throw_div_zero_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_throw_div_zero_from_code_PAL; +func_art_portable_throw_div_zero_from_code->setAttributes(func_art_portable_throw_div_zero_from_code_PAL); + +Function* func_art_portable_throw_array_bounds_from_code = mod->getFunction("art_portable_throw_array_bounds_from_code"); +if (!func_art_portable_throw_array_bounds_from_code) { +func_art_portable_throw_array_bounds_from_code = Function::Create( + /*Type=*/FuncTy_10, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_throw_array_bounds_from_code", mod); // (external, no body) +func_art_portable_throw_array_bounds_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_throw_array_bounds_from_code_PAL; +func_art_portable_throw_array_bounds_from_code->setAttributes(func_art_portable_throw_array_bounds_from_code_PAL); + +Function* func_art_portable_throw_no_such_method_from_code = mod->getFunction("art_portable_throw_no_such_method_from_code"); +if (!func_art_portable_throw_no_such_method_from_code) { +func_art_portable_throw_no_such_method_from_code = Function::Create( + /*Type=*/FuncTy_11, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_throw_no_such_method_from_code", mod); // (external, no body) +func_art_portable_throw_no_such_method_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_throw_no_such_method_from_code_PAL; +func_art_portable_throw_no_such_method_from_code->setAttributes(func_art_portable_throw_no_such_method_from_code_PAL); + +Function* func_art_portable_throw_null_pointer_exception_from_code = mod->getFunction("art_portable_throw_null_pointer_exception_from_code"); +if (!func_art_portable_throw_null_pointer_exception_from_code) { +func_art_portable_throw_null_pointer_exception_from_code = Function::Create( + /*Type=*/FuncTy_11, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_throw_null_pointer_exception_from_code", mod); // (external, no body) +func_art_portable_throw_null_pointer_exception_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_throw_null_pointer_exception_from_code_PAL; +func_art_portable_throw_null_pointer_exception_from_code->setAttributes(func_art_portable_throw_null_pointer_exception_from_code_PAL); + +Function* func_art_portable_throw_stack_overflow_from_code = mod->getFunction("art_portable_throw_stack_overflow_from_code"); +if (!func_art_portable_throw_stack_overflow_from_code) { +func_art_portable_throw_stack_overflow_from_code = Function::Create( + /*Type=*/FuncTy_9, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_throw_stack_overflow_from_code", mod); // (external, no body) +func_art_portable_throw_stack_overflow_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_throw_stack_overflow_from_code_PAL; +func_art_portable_throw_stack_overflow_from_code->setAttributes(func_art_portable_throw_stack_overflow_from_code_PAL); + +Function* func_art_portable_throw_exception_from_code = mod->getFunction("art_portable_throw_exception_from_code"); +if (!func_art_portable_throw_exception_from_code) { +func_art_portable_throw_exception_from_code = Function::Create( + /*Type=*/FuncTy_6, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_throw_exception_from_code", mod); // (external, no body) +func_art_portable_throw_exception_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_throw_exception_from_code_PAL; +func_art_portable_throw_exception_from_code->setAttributes(func_art_portable_throw_exception_from_code_PAL); + +Function* func_art_portable_find_catch_block_from_code = mod->getFunction("art_portable_find_catch_block_from_code"); +if (!func_art_portable_find_catch_block_from_code) { +func_art_portable_find_catch_block_from_code = Function::Create( + /*Type=*/FuncTy_12, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_find_catch_block_from_code", mod); // (external, no body) +func_art_portable_find_catch_block_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_find_catch_block_from_code_PAL; +func_art_portable_find_catch_block_from_code->setAttributes(func_art_portable_find_catch_block_from_code_PAL); + +Function* func_art_portable_alloc_object_from_code = mod->getFunction("art_portable_alloc_object_from_code"); +if (!func_art_portable_alloc_object_from_code) { +func_art_portable_alloc_object_from_code = Function::Create( + /*Type=*/FuncTy_13, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_alloc_object_from_code", mod); // (external, no body) +func_art_portable_alloc_object_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_alloc_object_from_code_PAL; +func_art_portable_alloc_object_from_code->setAttributes(func_art_portable_alloc_object_from_code_PAL); + +Function* func_art_portable_alloc_object_from_code_with_access_check = mod->getFunction("art_portable_alloc_object_from_code_with_access_check"); +if (!func_art_portable_alloc_object_from_code_with_access_check) { +func_art_portable_alloc_object_from_code_with_access_check = Function::Create( + /*Type=*/FuncTy_13, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_alloc_object_from_code_with_access_check", mod); // (external, no body) +func_art_portable_alloc_object_from_code_with_access_check->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_alloc_object_from_code_with_access_check_PAL; +func_art_portable_alloc_object_from_code_with_access_check->setAttributes(func_art_portable_alloc_object_from_code_with_access_check_PAL); + +Function* func_art_portable_alloc_array_from_code = mod->getFunction("art_portable_alloc_array_from_code"); +if (!func_art_portable_alloc_array_from_code) { +func_art_portable_alloc_array_from_code = Function::Create( + /*Type=*/FuncTy_14, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_alloc_array_from_code", mod); // (external, no body) +func_art_portable_alloc_array_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_alloc_array_from_code_PAL; +func_art_portable_alloc_array_from_code->setAttributes(func_art_portable_alloc_array_from_code_PAL); + +Function* func_art_portable_alloc_array_from_code_with_access_check = mod->getFunction("art_portable_alloc_array_from_code_with_access_check"); +if (!func_art_portable_alloc_array_from_code_with_access_check) { +func_art_portable_alloc_array_from_code_with_access_check = Function::Create( + /*Type=*/FuncTy_14, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_alloc_array_from_code_with_access_check", mod); // (external, no body) +func_art_portable_alloc_array_from_code_with_access_check->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_alloc_array_from_code_with_access_check_PAL; +func_art_portable_alloc_array_from_code_with_access_check->setAttributes(func_art_portable_alloc_array_from_code_with_access_check_PAL); + +Function* func_art_portable_check_and_alloc_array_from_code = mod->getFunction("art_portable_check_and_alloc_array_from_code"); +if (!func_art_portable_check_and_alloc_array_from_code) { +func_art_portable_check_and_alloc_array_from_code = Function::Create( + /*Type=*/FuncTy_14, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_check_and_alloc_array_from_code", mod); // (external, no body) +func_art_portable_check_and_alloc_array_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_check_and_alloc_array_from_code_PAL; +func_art_portable_check_and_alloc_array_from_code->setAttributes(func_art_portable_check_and_alloc_array_from_code_PAL); + +Function* func_art_portable_check_and_alloc_array_from_code_with_access_check = mod->getFunction("art_portable_check_and_alloc_array_from_code_with_access_check"); +if (!func_art_portable_check_and_alloc_array_from_code_with_access_check) { +func_art_portable_check_and_alloc_array_from_code_with_access_check = Function::Create( + /*Type=*/FuncTy_14, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_check_and_alloc_array_from_code_with_access_check", mod); // (external, no body) +func_art_portable_check_and_alloc_array_from_code_with_access_check->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_check_and_alloc_array_from_code_with_access_check_PAL; +func_art_portable_check_and_alloc_array_from_code_with_access_check->setAttributes(func_art_portable_check_and_alloc_array_from_code_with_access_check_PAL); + +Function* func_art_portable_find_instance_field_from_code = mod->getFunction("art_portable_find_instance_field_from_code"); +if (!func_art_portable_find_instance_field_from_code) { +func_art_portable_find_instance_field_from_code = Function::Create( + /*Type=*/FuncTy_15, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_find_instance_field_from_code", mod); // (external, no body) +func_art_portable_find_instance_field_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_find_instance_field_from_code_PAL; +func_art_portable_find_instance_field_from_code->setAttributes(func_art_portable_find_instance_field_from_code_PAL); + +Function* func_art_portable_find_static_field_from_code = mod->getFunction("art_portable_find_static_field_from_code"); +if (!func_art_portable_find_static_field_from_code) { +func_art_portable_find_static_field_from_code = Function::Create( + /*Type=*/FuncTy_15, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_find_static_field_from_code", mod); // (external, no body) +func_art_portable_find_static_field_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_find_static_field_from_code_PAL; +func_art_portable_find_static_field_from_code->setAttributes(func_art_portable_find_static_field_from_code_PAL); + +Function* func_art_portable_find_static_method_from_code_with_access_check = mod->getFunction("art_portable_find_static_method_from_code_with_access_check"); +if (!func_art_portable_find_static_method_from_code_with_access_check) { +func_art_portable_find_static_method_from_code_with_access_check = Function::Create( + /*Type=*/FuncTy_16, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_find_static_method_from_code_with_access_check", mod); // (external, no body) +func_art_portable_find_static_method_from_code_with_access_check->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_find_static_method_from_code_with_access_check_PAL; +func_art_portable_find_static_method_from_code_with_access_check->setAttributes(func_art_portable_find_static_method_from_code_with_access_check_PAL); + +Function* func_art_portable_find_direct_method_from_code_with_access_check = mod->getFunction("art_portable_find_direct_method_from_code_with_access_check"); +if (!func_art_portable_find_direct_method_from_code_with_access_check) { +func_art_portable_find_direct_method_from_code_with_access_check = Function::Create( + /*Type=*/FuncTy_16, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_find_direct_method_from_code_with_access_check", mod); // (external, no body) +func_art_portable_find_direct_method_from_code_with_access_check->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_find_direct_method_from_code_with_access_check_PAL; +func_art_portable_find_direct_method_from_code_with_access_check->setAttributes(func_art_portable_find_direct_method_from_code_with_access_check_PAL); + +Function* func_art_portable_find_virtual_method_from_code_with_access_check = mod->getFunction("art_portable_find_virtual_method_from_code_with_access_check"); +if (!func_art_portable_find_virtual_method_from_code_with_access_check) { +func_art_portable_find_virtual_method_from_code_with_access_check = Function::Create( + /*Type=*/FuncTy_16, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_find_virtual_method_from_code_with_access_check", mod); // (external, no body) +func_art_portable_find_virtual_method_from_code_with_access_check->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_find_virtual_method_from_code_with_access_check_PAL; +func_art_portable_find_virtual_method_from_code_with_access_check->setAttributes(func_art_portable_find_virtual_method_from_code_with_access_check_PAL); + +Function* func_art_portable_find_super_method_from_code_with_access_check = mod->getFunction("art_portable_find_super_method_from_code_with_access_check"); +if (!func_art_portable_find_super_method_from_code_with_access_check) { +func_art_portable_find_super_method_from_code_with_access_check = Function::Create( + /*Type=*/FuncTy_16, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_find_super_method_from_code_with_access_check", mod); // (external, no body) +func_art_portable_find_super_method_from_code_with_access_check->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_find_super_method_from_code_with_access_check_PAL; +func_art_portable_find_super_method_from_code_with_access_check->setAttributes(func_art_portable_find_super_method_from_code_with_access_check_PAL); + +Function* func_art_portable_find_interface_method_from_code_with_access_check = mod->getFunction("art_portable_find_interface_method_from_code_with_access_check"); +if (!func_art_portable_find_interface_method_from_code_with_access_check) { +func_art_portable_find_interface_method_from_code_with_access_check = Function::Create( + /*Type=*/FuncTy_16, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_find_interface_method_from_code_with_access_check", mod); // (external, no body) +func_art_portable_find_interface_method_from_code_with_access_check->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_find_interface_method_from_code_with_access_check_PAL; +func_art_portable_find_interface_method_from_code_with_access_check->setAttributes(func_art_portable_find_interface_method_from_code_with_access_check_PAL); + +Function* func_art_portable_find_interface_method_from_code = mod->getFunction("art_portable_find_interface_method_from_code"); +if (!func_art_portable_find_interface_method_from_code) { +func_art_portable_find_interface_method_from_code = Function::Create( + /*Type=*/FuncTy_16, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_find_interface_method_from_code", mod); // (external, no body) +func_art_portable_find_interface_method_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_find_interface_method_from_code_PAL; +func_art_portable_find_interface_method_from_code->setAttributes(func_art_portable_find_interface_method_from_code_PAL); + +Function* func_art_portable_initialize_static_storage_from_code = mod->getFunction("art_portable_initialize_static_storage_from_code"); +if (!func_art_portable_initialize_static_storage_from_code) { +func_art_portable_initialize_static_storage_from_code = Function::Create( + /*Type=*/FuncTy_13, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_initialize_static_storage_from_code", mod); // (external, no body) +func_art_portable_initialize_static_storage_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_initialize_static_storage_from_code_PAL; +func_art_portable_initialize_static_storage_from_code->setAttributes(func_art_portable_initialize_static_storage_from_code_PAL); + +Function* func_art_portable_initialize_type_from_code = mod->getFunction("art_portable_initialize_type_from_code"); +if (!func_art_portable_initialize_type_from_code) { +func_art_portable_initialize_type_from_code = Function::Create( + /*Type=*/FuncTy_13, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_initialize_type_from_code", mod); // (external, no body) +func_art_portable_initialize_type_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_initialize_type_from_code_PAL; +func_art_portable_initialize_type_from_code->setAttributes(func_art_portable_initialize_type_from_code_PAL); + +Function* func_art_portable_initialize_type_and_verify_access_from_code = mod->getFunction("art_portable_initialize_type_and_verify_access_from_code"); +if (!func_art_portable_initialize_type_and_verify_access_from_code) { +func_art_portable_initialize_type_and_verify_access_from_code = Function::Create( + /*Type=*/FuncTy_13, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_initialize_type_and_verify_access_from_code", mod); // (external, no body) +func_art_portable_initialize_type_and_verify_access_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_initialize_type_and_verify_access_from_code_PAL; +func_art_portable_initialize_type_and_verify_access_from_code->setAttributes(func_art_portable_initialize_type_and_verify_access_from_code_PAL); + +Function* func_art_portable_resolve_string_from_code = mod->getFunction("art_portable_resolve_string_from_code"); +if (!func_art_portable_resolve_string_from_code) { +func_art_portable_resolve_string_from_code = Function::Create( + /*Type=*/FuncTy_17, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_resolve_string_from_code", mod); // (external, no body) +func_art_portable_resolve_string_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_resolve_string_from_code_PAL; +func_art_portable_resolve_string_from_code->setAttributes(func_art_portable_resolve_string_from_code_PAL); + +Function* func_art_portable_set32_static_from_code = mod->getFunction("art_portable_set32_static_from_code"); +if (!func_art_portable_set32_static_from_code) { +func_art_portable_set32_static_from_code = Function::Create( + /*Type=*/FuncTy_18, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_set32_static_from_code", mod); // (external, no body) +func_art_portable_set32_static_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_set32_static_from_code_PAL; +func_art_portable_set32_static_from_code->setAttributes(func_art_portable_set32_static_from_code_PAL); + +Function* func_art_portable_set64_static_from_code = mod->getFunction("art_portable_set64_static_from_code"); +if (!func_art_portable_set64_static_from_code) { +func_art_portable_set64_static_from_code = Function::Create( + /*Type=*/FuncTy_19, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_set64_static_from_code", mod); // (external, no body) +func_art_portable_set64_static_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_set64_static_from_code_PAL; +func_art_portable_set64_static_from_code->setAttributes(func_art_portable_set64_static_from_code_PAL); + +Function* func_art_portable_set_obj_static_from_code = mod->getFunction("art_portable_set_obj_static_from_code"); +if (!func_art_portable_set_obj_static_from_code) { +func_art_portable_set_obj_static_from_code = Function::Create( + /*Type=*/FuncTy_20, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_set_obj_static_from_code", mod); // (external, no body) +func_art_portable_set_obj_static_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_set_obj_static_from_code_PAL; +func_art_portable_set_obj_static_from_code->setAttributes(func_art_portable_set_obj_static_from_code_PAL); + +Function* func_art_portable_get32_static_from_code = mod->getFunction("art_portable_get32_static_from_code"); +if (!func_art_portable_get32_static_from_code) { +func_art_portable_get32_static_from_code = Function::Create( + /*Type=*/FuncTy_21, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_get32_static_from_code", mod); // (external, no body) +func_art_portable_get32_static_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_get32_static_from_code_PAL; +func_art_portable_get32_static_from_code->setAttributes(func_art_portable_get32_static_from_code_PAL); + +Function* func_art_portable_get64_static_from_code = mod->getFunction("art_portable_get64_static_from_code"); +if (!func_art_portable_get64_static_from_code) { +func_art_portable_get64_static_from_code = Function::Create( + /*Type=*/FuncTy_22, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_get64_static_from_code", mod); // (external, no body) +func_art_portable_get64_static_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_get64_static_from_code_PAL; +func_art_portable_get64_static_from_code->setAttributes(func_art_portable_get64_static_from_code_PAL); + +Function* func_art_portable_get_obj_static_from_code = mod->getFunction("art_portable_get_obj_static_from_code"); +if (!func_art_portable_get_obj_static_from_code) { +func_art_portable_get_obj_static_from_code = Function::Create( + /*Type=*/FuncTy_23, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_get_obj_static_from_code", mod); // (external, no body) +func_art_portable_get_obj_static_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_get_obj_static_from_code_PAL; +func_art_portable_get_obj_static_from_code->setAttributes(func_art_portable_get_obj_static_from_code_PAL); + +Function* func_art_portable_set32_instance_from_code = mod->getFunction("art_portable_set32_instance_from_code"); +if (!func_art_portable_set32_instance_from_code) { +func_art_portable_set32_instance_from_code = Function::Create( + /*Type=*/FuncTy_24, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_set32_instance_from_code", mod); // (external, no body) +func_art_portable_set32_instance_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_set32_instance_from_code_PAL; +func_art_portable_set32_instance_from_code->setAttributes(func_art_portable_set32_instance_from_code_PAL); + +Function* func_art_portable_set64_instance_from_code = mod->getFunction("art_portable_set64_instance_from_code"); +if (!func_art_portable_set64_instance_from_code) { +func_art_portable_set64_instance_from_code = Function::Create( + /*Type=*/FuncTy_25, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_set64_instance_from_code", mod); // (external, no body) +func_art_portable_set64_instance_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_set64_instance_from_code_PAL; +func_art_portable_set64_instance_from_code->setAttributes(func_art_portable_set64_instance_from_code_PAL); + +Function* func_art_portable_set_obj_instance_from_code = mod->getFunction("art_portable_set_obj_instance_from_code"); +if (!func_art_portable_set_obj_instance_from_code) { +func_art_portable_set_obj_instance_from_code = Function::Create( + /*Type=*/FuncTy_26, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_set_obj_instance_from_code", mod); // (external, no body) +func_art_portable_set_obj_instance_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_set_obj_instance_from_code_PAL; +func_art_portable_set_obj_instance_from_code->setAttributes(func_art_portable_set_obj_instance_from_code_PAL); + +Function* func_art_portable_get32_instance_from_code = mod->getFunction("art_portable_get32_instance_from_code"); +if (!func_art_portable_get32_instance_from_code) { +func_art_portable_get32_instance_from_code = Function::Create( + /*Type=*/FuncTy_20, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_get32_instance_from_code", mod); // (external, no body) +func_art_portable_get32_instance_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_get32_instance_from_code_PAL; +func_art_portable_get32_instance_from_code->setAttributes(func_art_portable_get32_instance_from_code_PAL); + +Function* func_art_portable_get64_instance_from_code = mod->getFunction("art_portable_get64_instance_from_code"); +if (!func_art_portable_get64_instance_from_code) { +func_art_portable_get64_instance_from_code = Function::Create( + /*Type=*/FuncTy_27, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_get64_instance_from_code", mod); // (external, no body) +func_art_portable_get64_instance_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_get64_instance_from_code_PAL; +func_art_portable_get64_instance_from_code->setAttributes(func_art_portable_get64_instance_from_code_PAL); + +Function* func_art_portable_get_obj_instance_from_code = mod->getFunction("art_portable_get_obj_instance_from_code"); +if (!func_art_portable_get_obj_instance_from_code) { +func_art_portable_get_obj_instance_from_code = Function::Create( + /*Type=*/FuncTy_13, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_get_obj_instance_from_code", mod); // (external, no body) +func_art_portable_get_obj_instance_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_get_obj_instance_from_code_PAL; +func_art_portable_get_obj_instance_from_code->setAttributes(func_art_portable_get_obj_instance_from_code_PAL); + +Function* func_art_portable_decode_jobject_in_thread = mod->getFunction("art_portable_decode_jobject_in_thread"); +if (!func_art_portable_decode_jobject_in_thread) { +func_art_portable_decode_jobject_in_thread = Function::Create( + /*Type=*/FuncTy_28, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_decode_jobject_in_thread", mod); // (external, no body) +func_art_portable_decode_jobject_in_thread->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_decode_jobject_in_thread_PAL; +func_art_portable_decode_jobject_in_thread->setAttributes(func_art_portable_decode_jobject_in_thread_PAL); + +Function* func_art_portable_fill_array_data_from_code = mod->getFunction("art_portable_fill_array_data_from_code"); +if (!func_art_portable_fill_array_data_from_code) { +func_art_portable_fill_array_data_from_code = Function::Create( + /*Type=*/FuncTy_29, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_fill_array_data_from_code", mod); // (external, no body) +func_art_portable_fill_array_data_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_fill_array_data_from_code_PAL; +func_art_portable_fill_array_data_from_code->setAttributes(func_art_portable_fill_array_data_from_code_PAL); + +Function* func_art_portable_is_assignable_from_code = mod->getFunction("art_portable_is_assignable_from_code"); +if (!func_art_portable_is_assignable_from_code) { +func_art_portable_is_assignable_from_code = Function::Create( + /*Type=*/FuncTy_30, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_is_assignable_from_code", mod); // (external, no body) +func_art_portable_is_assignable_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_is_assignable_from_code_PAL; +func_art_portable_is_assignable_from_code->setAttributes(func_art_portable_is_assignable_from_code_PAL); + +Function* func_art_portable_check_cast_from_code = mod->getFunction("art_portable_check_cast_from_code"); +if (!func_art_portable_check_cast_from_code) { +func_art_portable_check_cast_from_code = Function::Create( + /*Type=*/FuncTy_5, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_check_cast_from_code", mod); // (external, no body) +func_art_portable_check_cast_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_check_cast_from_code_PAL; +func_art_portable_check_cast_from_code->setAttributes(func_art_portable_check_cast_from_code_PAL); + +Function* func_art_portable_check_put_array_element_from_code = mod->getFunction("art_portable_check_put_array_element_from_code"); +if (!func_art_portable_check_put_array_element_from_code) { +func_art_portable_check_put_array_element_from_code = Function::Create( + /*Type=*/FuncTy_5, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_check_put_array_element_from_code", mod); // (external, no body) +func_art_portable_check_put_array_element_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_check_put_array_element_from_code_PAL; +func_art_portable_check_put_array_element_from_code->setAttributes(func_art_portable_check_put_array_element_from_code_PAL); + +Function* func_art_d2l = mod->getFunction("art_d2l"); +if (!func_art_d2l) { +func_art_d2l = Function::Create( + /*Type=*/FuncTy_31, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_d2l", mod); // (external, no body) +func_art_d2l->setCallingConv(CallingConv::C); +} +AttributeSet func_art_d2l_PAL; +func_art_d2l->setAttributes(func_art_d2l_PAL); + +Function* func_art_d2i = mod->getFunction("art_d2i"); +if (!func_art_d2i) { +func_art_d2i = Function::Create( + /*Type=*/FuncTy_32, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_d2i", mod); // (external, no body) +func_art_d2i->setCallingConv(CallingConv::C); +} +AttributeSet func_art_d2i_PAL; +func_art_d2i->setAttributes(func_art_d2i_PAL); + +Function* func_art_f2l = mod->getFunction("art_f2l"); +if (!func_art_f2l) { +func_art_f2l = Function::Create( + /*Type=*/FuncTy_33, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_f2l", mod); // (external, no body) +func_art_f2l->setCallingConv(CallingConv::C); +} +AttributeSet func_art_f2l_PAL; +func_art_f2l->setAttributes(func_art_f2l_PAL); + +Function* func_art_f2i = mod->getFunction("art_f2i"); +if (!func_art_f2i) { +func_art_f2i = Function::Create( + /*Type=*/FuncTy_34, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_f2i", mod); // (external, no body) +func_art_f2i->setCallingConv(CallingConv::C); +} +AttributeSet func_art_f2i_PAL; +func_art_f2i->setAttributes(func_art_f2i_PAL); + +Function* func_art_portable_jni_method_start = mod->getFunction("art_portable_jni_method_start"); +if (!func_art_portable_jni_method_start) { +func_art_portable_jni_method_start = Function::Create( + /*Type=*/FuncTy_35, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_jni_method_start", mod); // (external, no body) +func_art_portable_jni_method_start->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_jni_method_start_PAL; +func_art_portable_jni_method_start->setAttributes(func_art_portable_jni_method_start_PAL); + +Function* func_art_portable_jni_method_start_synchronized = mod->getFunction("art_portable_jni_method_start_synchronized"); +if (!func_art_portable_jni_method_start_synchronized) { +func_art_portable_jni_method_start_synchronized = Function::Create( + /*Type=*/FuncTy_30, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_jni_method_start_synchronized", mod); // (external, no body) +func_art_portable_jni_method_start_synchronized->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_jni_method_start_synchronized_PAL; +func_art_portable_jni_method_start_synchronized->setAttributes(func_art_portable_jni_method_start_synchronized_PAL); + +Function* func_art_portable_jni_method_end = mod->getFunction("art_portable_jni_method_end"); +if (!func_art_portable_jni_method_end) { +func_art_portable_jni_method_end = Function::Create( + /*Type=*/FuncTy_15, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_jni_method_end", mod); // (external, no body) +func_art_portable_jni_method_end->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_jni_method_end_PAL; +func_art_portable_jni_method_end->setAttributes(func_art_portable_jni_method_end_PAL); + +Function* func_art_portable_jni_method_end_synchronized = mod->getFunction("art_portable_jni_method_end_synchronized"); +if (!func_art_portable_jni_method_end_synchronized) { +func_art_portable_jni_method_end_synchronized = Function::Create( + /*Type=*/FuncTy_36, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_jni_method_end_synchronized", mod); // (external, no body) +func_art_portable_jni_method_end_synchronized->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_jni_method_end_synchronized_PAL; +func_art_portable_jni_method_end_synchronized->setAttributes(func_art_portable_jni_method_end_synchronized_PAL); + +Function* func_art_portable_jni_method_end_with_reference = mod->getFunction("art_portable_jni_method_end_with_reference"); +if (!func_art_portable_jni_method_end_with_reference) { +func_art_portable_jni_method_end_with_reference = Function::Create( + /*Type=*/FuncTy_37, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_jni_method_end_with_reference", mod); // (external, no body) +func_art_portable_jni_method_end_with_reference->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_jni_method_end_with_reference_PAL; +func_art_portable_jni_method_end_with_reference->setAttributes(func_art_portable_jni_method_end_with_reference_PAL); + +Function* func_art_portable_jni_method_end_with_reference_synchronized = mod->getFunction("art_portable_jni_method_end_with_reference_synchronized"); +if (!func_art_portable_jni_method_end_with_reference_synchronized) { +func_art_portable_jni_method_end_with_reference_synchronized = Function::Create( + /*Type=*/FuncTy_38, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_jni_method_end_with_reference_synchronized", mod); // (external, no body) +func_art_portable_jni_method_end_with_reference_synchronized->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_jni_method_end_with_reference_synchronized_PAL; +func_art_portable_jni_method_end_with_reference_synchronized->setAttributes(func_art_portable_jni_method_end_with_reference_synchronized_PAL); + +Function* func_art_portable_is_exception_pending_from_code = mod->getFunction("art_portable_is_exception_pending_from_code"); +if (!func_art_portable_is_exception_pending_from_code) { +func_art_portable_is_exception_pending_from_code = Function::Create( + /*Type=*/FuncTy_39, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_is_exception_pending_from_code", mod); // (external, no body) +func_art_portable_is_exception_pending_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_is_exception_pending_from_code_PAL; +func_art_portable_is_exception_pending_from_code->setAttributes(func_art_portable_is_exception_pending_from_code_PAL); + +Function* func_art_portable_mark_gc_card_from_code = mod->getFunction("art_portable_mark_gc_card_from_code"); +if (!func_art_portable_mark_gc_card_from_code) { +func_art_portable_mark_gc_card_from_code = Function::Create( + /*Type=*/FuncTy_5, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_mark_gc_card_from_code", mod); // (external, no body) +func_art_portable_mark_gc_card_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_mark_gc_card_from_code_PAL; +func_art_portable_mark_gc_card_from_code->setAttributes(func_art_portable_mark_gc_card_from_code_PAL); + +Function* func_art_portable_proxy_invoke_handler_from_code = mod->getFunction("art_portable_proxy_invoke_handler_from_code"); +if (!func_art_portable_proxy_invoke_handler_from_code) { +func_art_portable_proxy_invoke_handler_from_code = Function::Create( + /*Type=*/FuncTy_40, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"art_portable_proxy_invoke_handler_from_code", mod); // (external, no body) +func_art_portable_proxy_invoke_handler_from_code->setCallingConv(CallingConv::C); +} +AttributeSet func_art_portable_proxy_invoke_handler_from_code_PAL; +func_art_portable_proxy_invoke_handler_from_code->setAttributes(func_art_portable_proxy_invoke_handler_from_code_PAL); + +// Global Variable Declarations + + +// Constant Definitions + +// Global Variable Definitions + +// Function Definitions + +return mod; + +} + +} // namespace llvm +} // namespace art diff --git a/compiler/llvm/intrinsic_func_list.def b/compiler/llvm/intrinsic_func_list.def new file mode 100644 index 0000000000..92537ba419 --- /dev/null +++ b/compiler/llvm/intrinsic_func_list.def @@ -0,0 +1,1803 @@ +/* + * 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. + */ + +// DEF_INTRINSICS_FUNC(ID, NAME, ATTR, RET_TYPE, +// ARG1_TYPE, ARG2_TYPE, ARG3_TYPE, ARG4_TYPE, ARG5_TYPE) +#ifndef DEF_INTRINSICS_FUNC +# error "missing DEF_INTRINSICS_FUNC definition!" +#endif + +#define _EVAL_DEF_INTRINSICS_FUNC(ID, NAME, ATTR, RET_TYPE, ...) \ + DEF_INTRINSICS_FUNC(ID, NAME, ATTR, RET_TYPE, __VA_ARGS__) + +#define _EXPAND_ARG0() kNone, kNone, kNone, kNone, kNone +#define _EXPAND_ARG1(ARG1) ARG1, kNone, kNone, kNone, kNone +#define _EXPAND_ARG2(ARG1, ARG2) ARG1, ARG2, kNone, kNone, kNone +#define _EXPAND_ARG3(ARG1, ARG2, ARG3) ARG1, ARG2, ARG3, kNone, kNone +#define _EXPAND_ARG4(ARG1, ARG2, ARG3, ARG4) ARG1, ARG2, ARG3, ARG4, kNone +#define _EXPAND_ARG5(ARG1, ARG2, ARG3, ARG4, ARG5) \ + ARG1, ARG2, ARG3, ARG4, ARG5 + +#define _JTYPE(TYPE, SPACE) _JTYPE_OF_ ## TYPE ## _UNDER_ ## SPACE + +// Note: These should be consistent with the type return from +// IRBuilder::GetJType([type], kArray). +#define _JTYPE_OF_kInt1Ty_UNDER_kArray kInt8Ty +#define _JTYPE_OF_kInt8Ty_UNDER_kArray kInt8Ty +#define _JTYPE_OF_kInt16Ty_UNDER_kArray kInt16Ty +#define _JTYPE_OF_kInt32Ty_UNDER_kArray kInt32Ty +#define _JTYPE_OF_kInt64Ty_UNDER_kArray kInt64Ty +#define _JTYPE_OF_kJavaObjectTy_UNDER_kArray kJavaObjectTy + +// Note: These should be consistent with the type return from +// IRBuilder::GetJType([type], kField). +#define _JTYPE_OF_kInt1Ty_UNDER_kField kInt32Ty +#define _JTYPE_OF_kInt8Ty_UNDER_kField kInt32Ty +#define _JTYPE_OF_kInt16Ty_UNDER_kField kInt32Ty +#define _JTYPE_OF_kInt32Ty_UNDER_kField kInt32Ty +#define _JTYPE_OF_kInt64Ty_UNDER_kField kInt64Ty +#define _JTYPE_OF_kJavaObjectTy_UNDER_kField kJavaObjectTy + +//---------------------------------------------------------------------------- +// Thread +//---------------------------------------------------------------------------- + +// Thread* art_portable_get_current_thread() +_EVAL_DEF_INTRINSICS_FUNC(GetCurrentThread, + art_portable_get_current_thread, + kAttrReadNone | kAttrNoThrow, + kJavaThreadTy, + _EXPAND_ARG0()) + +// void art_portable_test_suspend(Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(TestSuspend, + art_portable_test_suspend, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG1(kJavaThreadTy)) + +// void art_portable_check_suspend() /* Expands to GetCurrentThread/TestSuspend */ +_EVAL_DEF_INTRINSICS_FUNC(CheckSuspend, + art_portable_check_suspend, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG0()) + +// void art_portable_mark_gc_card(Object* new_value, Object* object) +_EVAL_DEF_INTRINSICS_FUNC(MarkGCCard, + art_portable_mark_gc_card, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy)) + +//---------------------------------------------------------------------------- +// Exception +//---------------------------------------------------------------------------- + +// Should not expand - introduces the catch targets for a potentially +// throwing instruction. The result is a switch key and this +// instruction will be followed by a switch statement. The catch +// targets will be enumerated as cases of the switch, with the fallthrough +// designating the block containing the potentially throwing instruction. +// bool art_portable_catch_targets(int dex_pc) +_EVAL_DEF_INTRINSICS_FUNC(CatchTargets, + art_portable_catch_targets, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32ConstantTy)) + +// void art_portable_throw_exception(JavaObject* exception) +_EVAL_DEF_INTRINSICS_FUNC(ThrowException, + art_portable_throw_exception, + kAttrDoThrow, + kVoidTy, + _EXPAND_ARG1(kJavaObjectTy)) + +// void art_portable_hl_throw_exception(JavaObject* exception) +_EVAL_DEF_INTRINSICS_FUNC(HLThrowException, + art_portable_hl_throw_exception, + kAttrDoThrow, + kVoidTy, + _EXPAND_ARG1(kJavaObjectTy)) + +// JavaObject* art_portable_get_current_exception() +_EVAL_DEF_INTRINSICS_FUNC(GetException, + art_portable_get_current_exception, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG0()) + +// bool art_portable_is_exception_pending() +_EVAL_DEF_INTRINSICS_FUNC(IsExceptionPending, + art_portable_is_exception_pending, + kAttrReadOnly | kAttrNoThrow, + kInt1Ty, + _EXPAND_ARG0()) + +// int art_portable_find_catch_block(Method* method, int try_item_offset) +_EVAL_DEF_INTRINSICS_FUNC(FindCatchBlock, + art_portable_find_catch_block, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kJavaMethodTy, kInt32ConstantTy)) + +// void art_portable_throw_div_zero() +_EVAL_DEF_INTRINSICS_FUNC(ThrowDivZeroException, + art_portable_throw_div_zero, + kAttrDoThrow, + kVoidTy, + _EXPAND_ARG0()) + +// void art_portable_throw_null_pointer_exception(uint32_t dex_pc) +_EVAL_DEF_INTRINSICS_FUNC(ThrowNullPointerException, + art_portable_throw_null_pointer_exception, + kAttrDoThrow, + kVoidTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +// void art_portable_throw_array_bounds(int index, int array_len) +_EVAL_DEF_INTRINSICS_FUNC(ThrowIndexOutOfBounds, + art_portable_throw_array_bounds, + kAttrDoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kInt32Ty)) + +//---------------------------------------------------------------------------- +// ConstString +//---------------------------------------------------------------------------- + +// JavaObject* art_portable_const_string(uint32_t string_idx) +_EVAL_DEF_INTRINSICS_FUNC(ConstString, + art_portable_const_string, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +// JavaObject* art_portable_load_string_from_dex_cache(Method* method, uint32_t string_idx) +_EVAL_DEF_INTRINSICS_FUNC(LoadStringFromDexCache, + art_portable_load_string_from_dex_cache, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +// JavaObject* art_portable_resolve_string(Method* method, uint32_t string_idx) +_EVAL_DEF_INTRINSICS_FUNC(ResolveString, + art_portable_resolve_string, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG2(kJavaMethodTy, kInt32ConstantTy)) + +//---------------------------------------------------------------------------- +// ConstClass +//---------------------------------------------------------------------------- + +// JavaObject* art_portable_const_class(uint32_t type_idx) +_EVAL_DEF_INTRINSICS_FUNC(ConstClass, + art_portable_const_class, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +// JavaObject* art_portable_initialize_type_and_verify_access(uint32_t type_idx, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(InitializeTypeAndVerifyAccess, + art_portable_initialize_type_and_verify_access, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy)) + +// JavaObject* art_portable_load_type_from_dex_cache(uint32_t type_idx) +_EVAL_DEF_INTRINSICS_FUNC(LoadTypeFromDexCache, + art_portable_load_type_from_dex_cache, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +// JavaObject* art_portable_initialize_type(uint32_t type_idx, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(InitializeType, + art_portable_initialize_type, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy)) + +//---------------------------------------------------------------------------- +// Lock +//---------------------------------------------------------------------------- + +// void art_portable_lock_object(JavaObject* obj, Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(LockObject, + art_portable_lock_object, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kJavaObjectTy, kJavaThreadTy)) + +// void art_portable_unlock_object(JavaObject* obj, Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(UnlockObject, + art_portable_unlock_object, + kAttrNone, + kVoidTy, + _EXPAND_ARG2(kJavaObjectTy, kJavaThreadTy)) + +//---------------------------------------------------------------------------- +// Cast +//---------------------------------------------------------------------------- + +// void art_portable_check_cast(JavaObject* dest_type, JavaObject* src_type) +_EVAL_DEF_INTRINSICS_FUNC(CheckCast, + art_portable_check_cast, + kAttrNone, + kVoidTy, + _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy)) + +// void art_portable_hl_check_cast(uint32_t type_idx, JavaObject* obj) +_EVAL_DEF_INTRINSICS_FUNC(HLCheckCast, + art_portable_hl_check_cast, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy)) + +// int art_portable_is_assignable(JavaObject* dest_type, JavaObject* src_type) +_EVAL_DEF_INTRINSICS_FUNC(IsAssignable, + art_portable_is_assignable, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy)) + +//---------------------------------------------------------------------------- +// Allocation +//---------------------------------------------------------------------------- + +// JavaObject* art_portable_alloc_object(uint32_t type_idx, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(AllocObject, + art_portable_alloc_object, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy)) + +// JavaObject* art_portable_alloc_object_with_access_check(uint32_t type_idx, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(AllocObjectWithAccessCheck, + art_portable_alloc_object_with_access_check, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy)) + +//---------------------------------------------------------------------------- +// Instance +//---------------------------------------------------------------------------- + +// JavaObject* art_portable_new_instance(uint32_t type_idx) +_EVAL_DEF_INTRINSICS_FUNC(NewInstance, + art_portable_new_instance, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG1(kInt32Ty)) + +// bool art_portable_instance_of(uint32_t type_idx, JavaObject* ref) +_EVAL_DEF_INTRINSICS_FUNC(InstanceOf, + art_portable_instance_of, + kAttrNone, + kInt32Ty, + _EXPAND_ARG2(kInt32Ty, kJavaObjectTy)) + +//---------------------------------------------------------------------------- +// Array +//---------------------------------------------------------------------------- + +// JavaObject* art_portable_new_array(uint32_t type_idx, uint32_t array_size) +_EVAL_DEF_INTRINSICS_FUNC(NewArray, + art_portable_new_array, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG2(kInt32ConstantTy, kInt32Ty)) + +// uint32_t art_portable_opt_array_length(int32_t opt_flags, JavaObject* array) +_EVAL_DEF_INTRINSICS_FUNC(OptArrayLength, + art_portable_opt_array_length, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kInt32Ty, kJavaObjectTy)) + +// uint32_t art_portable_array_length(JavaObject* array) +_EVAL_DEF_INTRINSICS_FUNC(ArrayLength, + art_portable_array_length, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kJavaObjectTy)) + +// JavaObject* art_portable_alloc_array(uint32_t type_idx, +// Method* referrer, +// uint32_t length, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(AllocArray, + art_portable_alloc_array, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32Ty, kJavaThreadTy)) + +// JavaObject* art_portable_alloc_array_with_access_check(uint32_t type_idx, +// Method* referrer, +// uint32_t length, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(AllocArrayWithAccessCheck, + art_portable_alloc_array_with_access_check, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32Ty, kJavaThreadTy)) + +// JavaObject* art_portable_check_and_alloc_array(uint32_t type_idx, +// Method* referrer, +// uint32_t length, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(CheckAndAllocArray, + art_portable_check_and_alloc_array, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32ConstantTy, kJavaThreadTy)) + +// JavaObject* art_portable_check_and_alloc_array_with_access_check(uint32_t type_idx, +// Method* referrer, +// uint32_t length, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(CheckAndAllocArrayWithAccessCheck, + art_portable_check_and_alloc_array_with_access_check, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kInt32ConstantTy, kJavaThreadTy)) + +// art_portable_aget_* and art_portable_aput_* never generate exception since the +// necessary checking on arguments (e.g., array and index) has already done +// before invocation of these intrinsics. +// +// [type] void art_portable_aget_[type](JavaObject* array, uint32_t index) +_EVAL_DEF_INTRINSICS_FUNC(ArrayGet, + art_portable_aget, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt32Ty, kArray), + _EXPAND_ARG2(kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayGetWide, + art_portable_aget_wide, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt64Ty, kArray), + _EXPAND_ARG2(kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayGetObject, + art_portable_aget_object, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kJavaObjectTy, kArray), + _EXPAND_ARG2(kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayGetBoolean, + art_portable_aget_boolean, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt1Ty, kArray), + _EXPAND_ARG2(kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayGetByte, + art_portable_aget_byte, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt8Ty, kArray), + _EXPAND_ARG2(kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayGetChar, + art_portable_aget_char, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt16Ty, kArray), + _EXPAND_ARG2(kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayGetShort, + art_portable_aget_short, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt16Ty, kArray), + _EXPAND_ARG2(kJavaObjectTy, kInt32Ty)) + +// void art_portable_aput_[type]([type] value, JavaObject* array, uint32_t index) +_EVAL_DEF_INTRINSICS_FUNC(ArrayPut, + art_portable_aput, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG3(_JTYPE(kInt32Ty, kArray), kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayPutWide, + art_portable_aput_wide, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG3(_JTYPE(kInt64Ty, kArray), kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayPutObject, + art_portable_aput_object, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG3(_JTYPE(kJavaObjectTy, kArray), kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayPutBoolean, + art_portable_aput_boolean, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG3(_JTYPE(kInt1Ty, kArray), kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayPutByte, + art_portable_aput_byte, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG3(_JTYPE(kInt8Ty, kArray), kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayPutChar, + art_portable_aput_char, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG3(_JTYPE(kInt16Ty, kArray), kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(ArrayPutShort, + art_portable_aput_short, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG3(_JTYPE(kInt16Ty, kArray), kJavaObjectTy, kInt32Ty)) + +// void art_portable_check_put_array_element(JavaObject* value, JavaObject* array) +_EVAL_DEF_INTRINSICS_FUNC(CheckPutArrayElement, + art_portable_check_put_array_element, + kAttrNone, + kVoidTy, + _EXPAND_ARG2(kJavaObjectTy, kJavaObjectTy)) + +// void art_portable_filled_new_array(Array* array, +// uint32_t elem_jty, ...) +_EVAL_DEF_INTRINSICS_FUNC(FilledNewArray, + art_portable_filled_new_array, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kVarArgTy)) + +// void art_portable_fill_array_data(Method* referrer, +// uint32_t dex_pc, +// Array* array, +// uint32_t payload_offset) +_EVAL_DEF_INTRINSICS_FUNC(FillArrayData, + art_portable_fill_array_data, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kJavaMethodTy, kInt32ConstantTy, kJavaObjectTy, kInt32ConstantTy)) + +// void art_portable_hl_fill_array_data(int32_t offset, JavaObject* array) +_EVAL_DEF_INTRINSICS_FUNC(HLFillArrayData, + art_portable_hl_fill_array_data, + kAttrNone, + kVoidTy, + _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy)) + +//---------------------------------------------------------------------------- +// Instance Field +//---------------------------------------------------------------------------- + +// [type] art_portable_iget_[type](uint32_t field_idx, +// Method* referrer, +// JavaObject* obj) +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGet, + art_portable_iget, + kAttrNone, + _JTYPE(kInt32Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetWide, + art_portable_iget_wide, + kAttrNone, + _JTYPE(kInt64Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetObject, + art_portable_iget_object, + kAttrNone, + _JTYPE(kJavaObjectTy, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetBoolean, + art_portable_iget_boolean, + kAttrNone, + _JTYPE(kInt1Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetByte, + art_portable_iget_byte, + kAttrNone, + _JTYPE(kInt8Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetChar, + art_portable_iget_char, + kAttrNone, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetShort, + art_portable_iget_short, + kAttrNone, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy)) + +// [type] art_portable_iget_[type].fast(int field_offset, +// bool is_volatile, +// JavaObject* obj) +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetFast, + art_portable_iget.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt32Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetWideFast, + art_portable_iget_wide.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt64Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetObjectFast, + art_portable_iget_object.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kJavaObjectTy, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetBooleanFast, + art_portable_iget_boolean.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt1Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetByteFast, + art_portable_iget_byte.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt8Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetCharFast, + art_portable_iget_char.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldGetShortFast, + art_portable_iget_short.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy)) + +// void art_portable_iput_[type](uint32_t field_idx, +// Method* referrer, +// JavaObject* obj, +// [type] new_value) +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPut, + art_portable_iput, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt32Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutWide, + art_portable_iput_wide, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt64Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutObject, + art_portable_iput_object, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kJavaObjectTy, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutBoolean, + art_portable_iput_boolean, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt1Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutByte, + art_portable_iput_byte, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt8Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutChar, + art_portable_iput_char, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutShort, + art_portable_iput_short, + kAttrNone, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaMethodTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField))) + +// void art_portable_iput_[type].fast(int field_offset, +// bool is_volatile, +// JavaObject* obj, +// [type] new_value) +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutFast, + art_portable_iput.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt32Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutWideFast, + art_portable_iput_wide.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt64Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutObjectFast, + art_portable_iput_object.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kJavaObjectTy, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutBooleanFast, + art_portable_iput_boolean.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt1Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutByteFast, + art_portable_iput_byte.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt8Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutCharFast, + art_portable_iput_char.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(InstanceFieldPutShortFast, + art_portable_iput_short.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32ConstantTy, kInt1ConstantTy, kJavaObjectTy, _JTYPE(kInt16Ty, kField))) + +//---------------------------------------------------------------------------- +// Static Field +//---------------------------------------------------------------------------- + +// [type] art_portable_sget_[type](uint32_t field_idx, Method* referrer) +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGet, + art_portable_sget, + kAttrNone, + _JTYPE(kInt32Ty, kField), + _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetWide, + art_portable_sget_wide, + kAttrNone, + _JTYPE(kInt64Ty, kField), + _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetObject, + art_portable_sget_object, + kAttrNone, + _JTYPE(kJavaObjectTy, kField), + _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetBoolean, + art_portable_sget_boolean, + kAttrNone, + _JTYPE(kInt1Ty, kField), + _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetByte, + art_portable_sget_byte, + kAttrNone, + _JTYPE(kInt8Ty, kField), + _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetChar, + art_portable_sget_char, + kAttrNone, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetShort, + art_portable_sget_short, + kAttrNone, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG2(kInt32ConstantTy, kJavaMethodTy)) + +// [type] art_portable_sget_[type].fast(JavaObject* ssb, +// int field_offset, +// bool is_volatile) +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetFast, + art_portable_sget.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt32Ty, kField), + _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetWideFast, + art_portable_sget_wide.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt64Ty, kField), + _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetObjectFast, + art_portable_sget_object.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kJavaObjectTy, kField), + _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetBooleanFast, + art_portable_sget_boolean.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt1Ty, kField), + _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetByteFast, + art_portable_sget_byte.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt8Ty, kField), + _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetCharFast, + art_portable_sget_char.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy)) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldGetShortFast, + art_portable_sget_short.fast, + kAttrReadOnly | kAttrNoThrow, + _JTYPE(kInt16Ty, kField), + _EXPAND_ARG3(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy)) + +// void art_portable_sput_[type](uint32_t field_idx, +// Method* referrer, +// [type] new_value) +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPut, + art_portable_sput, + kAttrNone, + kVoidTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt32Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutWide, + art_portable_sput_wide, + kAttrNone, + kVoidTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt64Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutObject, + art_portable_sput_object, + kAttrNone, + kVoidTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kJavaObjectTy, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutBoolean, + art_portable_sput_boolean, + kAttrNone, + kVoidTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt1Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutByte, + art_portable_sput_byte, + kAttrNone, + kVoidTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt8Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutChar, + art_portable_sput_char, + kAttrNone, + kVoidTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt16Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutShort, + art_portable_sput_short, + kAttrNone, + kVoidTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, _JTYPE(kInt16Ty, kField))) + +// void art_portable_sput_[type].fast(JavaObject* ssb, +// int field_offset, +// bool is_volatile, +// [type] new_value) +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutFast, + art_portable_sput.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt32Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutWideFast, + art_portable_sput_wide.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt64Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutObjectFast, + art_portable_sput_object.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kJavaObjectTy, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutBooleanFast, + art_portable_sput_boolean.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt1Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutByteFast, + art_portable_sput_byte.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt8Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutCharFast, + art_portable_sput_char.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt16Ty, kField))) + +_EVAL_DEF_INTRINSICS_FUNC(StaticFieldPutShortFast, + art_portable_sput_short.fast, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kJavaObjectTy, kInt32ConstantTy, kInt1ConstantTy, _JTYPE(kInt16Ty, kField))) + +// JavaObject* art_portable_load_declaring_class_ssb(Method* method) +// Load the static storage base of the class that given method resides +_EVAL_DEF_INTRINSICS_FUNC(LoadDeclaringClassSSB, + art_portable_load_declaring_class_ssb, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kJavaMethodTy)) + +// JavaObject* art_portable_load_class_ssb_from_dex_cache(uint32_t type_idx) +_EVAL_DEF_INTRINSICS_FUNC(LoadClassSSBFromDexCache, + art_portable_load_class_ssb_from_dex_cache, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +// JavaObject* art_portable_init_and_load_class_ssb(uint32_t type_idx, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(InitializeAndLoadClassSSB, + art_portable_init_and_load_class_ssb, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG3(kInt32ConstantTy, kJavaMethodTy, kJavaThreadTy)) + +//---------------------------------------------------------------------------- +// High-level Array get/put +// +// Similar to art_portable_aget/aput_xxx, but checks not yet performed. +// OptFlags contain info describing whether frontend has determined that +// null check and/or array bounds check may be skipped. +// +// [type] void art_portable_hl_aget_[type](int optFlags, JavaObject* array, uint32_t index) +_EVAL_DEF_INTRINSICS_FUNC(HLArrayGet, + art_portable_hl_aget, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetFloat, + art_portable_hl_aget_float, + kAttrReadOnly | kAttrNoThrow, + kFloatTy, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetWide, + art_portable_hl_aget_wide, + kAttrReadOnly | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetDouble, + art_portable_hl_aget_double, + kAttrReadOnly | kAttrNoThrow, + kDoubleTy, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetObject, + art_portable_hl_aget_object, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetBoolean, + art_portable_hl_aget_boolean, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetByte, + art_portable_hl_aget_byte, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetChar, + art_portable_hl_aget_char, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayGetShort, + art_portable_hl_aget_short, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +// void art_portable_aput_[type](int optFlags, [type] value, JavaObject* array, uint32_t index) +_EVAL_DEF_INTRINSICS_FUNC(HLArrayPut, + art_portable_hl_aput, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutFloat, + art_portable_hl_aput_float, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kFloatTy, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutWide, + art_portable_hl_aput_wide, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt64Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutDouble, + art_portable_hl_aput_double, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kDoubleTy, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutObject, + art_portable_hl_aput_object, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kJavaObjectTy, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutBoolean, + art_portable_hl_aput_boolean, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutByte, + art_portable_hl_aput_byte, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutChar, + art_portable_hl_aput_char, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLArrayPutShort, + art_portable_hl_aput_short, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +//---------------------------------------------------------------------------- +// High-level Instance get/put +// +// Similar to art_portable_iget/iput_xxx, but checks not yet performed. +// OptFlags contain info describing whether frontend has determined that +// null check may be skipped. +// +// [type] void art_portable_hl_iget_[type](int optFlags, JavaObject* obj, uint32_t field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLIGet, + art_portable_hl_iget, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIGetFloat, + art_portable_hl_iget_float, + kAttrReadOnly | kAttrNoThrow, + kFloatTy, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIGetWide, + art_portable_hl_iget_wide, + kAttrReadOnly | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIGetDouble, + art_portable_hl_iget_double, + kAttrReadOnly | kAttrNoThrow, + kDoubleTy, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIGetObject, + art_portable_hl_iget_object, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIGetBoolean, + art_portable_hl_iget_boolean, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIGetByte, + art_portable_hl_iget_byte, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIGetChar, + art_portable_hl_iget_char, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIGetShort, + art_portable_hl_iget_short, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG3(kInt32Ty, kJavaObjectTy, kInt32Ty)) + +// void art_portable_iput_[type](int optFlags, [type] value, JavaObject* obj, uint32_t field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLIPut, + art_portable_hl_iput, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIPutFloat, + art_portable_hl_iput_float, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kFloatTy, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIPutWide, + art_portable_hl_iput_wide, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt64Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIPutDouble, + art_portable_hl_iput_double, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kDoubleTy, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIPutObject, + art_portable_hl_iput_object, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kJavaObjectTy, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIPutBoolean, + art_portable_hl_iput_boolean, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIPutByte, + art_portable_hl_iput_byte, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIPutChar, + art_portable_hl_iput_char, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(HLIPutShort, + art_portable_hl_iput_short, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG4(kInt32Ty, kInt32Ty, kJavaObjectTy, kInt32Ty)) + +//---------------------------------------------------------------------------- +// High-level Invokes (fast-path determination not yet performed) +// +// NOTE: We expect these intrinsics to be temporary. Once calling conventions are +// fully merged, the unified front end will lower down to the +// InvokeRetxxx() intrinsics in the next section and these will be +// removed. +// +// arg0: InvokeType [ignored if FilledNewArray] +// arg1: method_idx [ignored if FilledNewArray] +// arg2: optimization_flags (primary to note whether null checking is needed) +// [arg3..argN]: actual arguments +//---------------------------------------------------------------------------- +// INVOKE method returns void +_EVAL_DEF_INTRINSICS_FUNC(HLInvokeVoid, + art_portable_hl_invoke.void, + kAttrNone, + kVoidTy, + _EXPAND_ARG1(kVarArgTy)) + +// INVOKE method returns object +_EVAL_DEF_INTRINSICS_FUNC(HLInvokeObj, + art_portable_hl_invoke.obj, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG1(kVarArgTy)) + +// INVOKE method returns int +_EVAL_DEF_INTRINSICS_FUNC(HLInvokeInt, + art_portable_hl_invoke.i32, + kAttrNone, + kInt32Ty, + _EXPAND_ARG1(kVarArgTy)) + +// INVOKE method returns float +_EVAL_DEF_INTRINSICS_FUNC(HLInvokeFloat, + art_portable_hl_invoke.f32, + kAttrNone, + kFloatTy, + _EXPAND_ARG1(kVarArgTy)) + +// INVOKE method returns long +_EVAL_DEF_INTRINSICS_FUNC(HLInvokeLong, + art_portable_hl_invoke.i64, + kAttrNone, + kInt64Ty, + _EXPAND_ARG1(kVarArgTy)) + +// INVOKE method returns double +_EVAL_DEF_INTRINSICS_FUNC(HLInvokeDouble, + art_portable_hl_invoke.f64, + kAttrNone, + kDoubleTy, + _EXPAND_ARG1(kVarArgTy)) + +// FILLED_NEW_ARRAY returns object +_EVAL_DEF_INTRINSICS_FUNC(HLFilledNewArray, + art_portable_hl_filled_new_array, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG1(kVarArgTy)) + +//---------------------------------------------------------------------------- +// Invoke +//---------------------------------------------------------------------------- + +// Method* art_portable_find_static_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindStaticMethodWithAccessCheck, + art_portable_find_static_method_with_access_check, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// Method* art_portable_find_direct_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindDirectMethodWithAccessCheck, + art_portable_find_direct_method_with_access_check, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// Method* art_portable_find_virtual_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindVirtualMethodWithAccessCheck, + art_portable_find_virtual_method_with_access_check, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// Method* art_portable_find_super_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindSuperMethodWithAccessCheck, + art_portable_find_super_method_with_access_check, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// Method* art_portable_find_interface_method_with_access_check(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(FindInterfaceMethodWithAccessCheck, + art_portable_find_interface_method_with_access_check, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// Method* art_portable_get_sd_callee_method_obj_addr(uint32_t method_idx) +_EVAL_DEF_INTRINSICS_FUNC(GetSDCalleeMethodObjAddrFast, + art_portable_get_sd_callee_method_obj_addr_fast, + kAttrReadOnly | kAttrNoThrow, + kJavaMethodTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +// Method* art_portable_get_virtual_callee_method_obj_addr(uint32_t vtable_idx, +// JavaObject* this) +_EVAL_DEF_INTRINSICS_FUNC(GetVirtualCalleeMethodObjAddrFast, + art_portable_get_virtual_callee_method_obj_addr_fast, + kAttrReadOnly | kAttrNoThrow, + kJavaMethodTy, + _EXPAND_ARG2(kInt32ConstantTy, kJavaObjectTy)) + +// Method* art_portable_get_interface_callee_method_obj_addr(uint32_t method_idx, +// JavaObject* this, +// Method* referrer, +// Thread* thread) +_EVAL_DEF_INTRINSICS_FUNC(GetInterfaceCalleeMethodObjAddrFast, + art_portable_get_interface_callee_method_obj_addr_fast, + kAttrNone, + kJavaMethodTy, + _EXPAND_ARG4(kInt32ConstantTy, kJavaObjectTy, kJavaMethodTy, kJavaThreadTy)) + +// [type] art_portable_invoke.[type](Method* callee, ...) +// INVOKE method returns void +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetVoid, + art_portable_invoke.void, + kAttrNone, + kVoidTy, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type boolean +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetBoolean, + art_portable_invoke.bool, + kAttrNone, + kInt1Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type byte +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetByte, + art_portable_invoke.byte, + kAttrNone, + kInt8Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type char +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetChar, + art_portable_invoke.char, + kAttrNone, + kInt16Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type short +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetShort, + art_portable_invoke.short, + kAttrNone, + kInt16Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type int +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetInt, + art_portable_invoke.int, + kAttrNone, + kInt32Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type long +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetLong, + art_portable_invoke.long, + kAttrNone, + kInt64Ty, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type float +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetFloat, + art_portable_invoke.float, + kAttrNone, + kFloatTy, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type double +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetDouble, + art_portable_invoke.double, + kAttrNone, + kDoubleTy, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +// INVOKE method returns the value of type "object" +_EVAL_DEF_INTRINSICS_FUNC(InvokeRetObject, + art_portable_invoke.object, + kAttrNone, + kJavaObjectTy, + _EXPAND_ARG2(kJavaMethodTy, kVarArgTy)) + +//---------------------------------------------------------------------------- +// Math +//---------------------------------------------------------------------------- + +// int art_portable_{div,rem}_int(int a, int b) +_EVAL_DEF_INTRINSICS_FUNC(DivInt, + art_portable_div_int, + kAttrReadNone | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kInt32Ty, kInt32Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(RemInt, + art_portable_rem_int, + kAttrReadNone | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kInt32Ty, kInt32Ty)) + +// long art_portable_{div,rem}_long(long a, long b) +_EVAL_DEF_INTRINSICS_FUNC(DivLong, + art_portable_div_long, + kAttrReadNone | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG2(kInt64Ty, kInt64Ty)) + +_EVAL_DEF_INTRINSICS_FUNC(RemLong, + art_portable_rem_long, + kAttrReadNone | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG2(kInt64Ty, kInt64Ty)) + +// int64_t art_portable_d2l(double f) +_EVAL_DEF_INTRINSICS_FUNC(D2L, + art_portable_d2l, + kAttrReadNone | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG1(kDoubleTy)) + +// int32_t art_portable_d2l(double f) +_EVAL_DEF_INTRINSICS_FUNC(D2I, + art_portable_d2i, + kAttrReadNone | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kDoubleTy)) + +// int64_t art_portable_f2l(float f) +_EVAL_DEF_INTRINSICS_FUNC(F2L, + art_portable_f2l, + kAttrReadNone | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG1(kFloatTy)) + +// int32_t art_portable_f2i(float f) +_EVAL_DEF_INTRINSICS_FUNC(F2I, + art_portable_f2i, + kAttrReadNone | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kFloatTy)) + +//---------------------------------------------------------------------------- +// sput intrinsics to assist MIR to Greenland_ir conversion. +// "HL" versions - will be deprecated when fast/slow path handling done +// in the common frontend. +//---------------------------------------------------------------------------- + +// void sput_hl(int field_idx, int val) +_EVAL_DEF_INTRINSICS_FUNC(HLSput, + art_portable_hl_sput, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kInt32Ty)) + +// void sput_hl_object(int field_idx, object* val) +_EVAL_DEF_INTRINSICS_FUNC(HLSputObject, + art_portable_hl_sput_object, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kJavaObjectTy)) + +// void sput_hl_boolean(int field_idx, kInt1Ty) +_EVAL_DEF_INTRINSICS_FUNC(HLSputBoolean, + art_portable_hl_sput_boolean, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kInt32Ty)) + +// void sput_hl_byte(int field_idx, int val) +_EVAL_DEF_INTRINSICS_FUNC(HLSputByte, + art_portable_hl_sput_byte, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kInt32Ty)) + +// void sput_hl_char(int field_idx, kInt16Ty val) +_EVAL_DEF_INTRINSICS_FUNC(HLSputChar, + art_portable_hl_sput_char, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kInt32Ty)) + +// void sput_hl_short(int field_idx, int val) +_EVAL_DEF_INTRINSICS_FUNC(HLSputShort, + art_portable_hl_sput_short, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kInt32Ty)) + +// void sput_hl_wide(int field_idx, long val) +_EVAL_DEF_INTRINSICS_FUNC(HLSputWide, + art_portable_hl_sput_wide, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kInt64Ty)) + +// void sput_hl_double(int field_idx, double val) +_EVAL_DEF_INTRINSICS_FUNC(HLSputDouble, + art_portable_hl_sput_double, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kDoubleTy)) + +// void sput_hl_float(int field_idx, float val) +_EVAL_DEF_INTRINSICS_FUNC(HLSputFloat, + art_portable_hl_sput_float, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kFloatTy)) + +//---------------------------------------------------------------------------- +// sget intrinsics to assist MIR to Greenland_ir conversion. +// "HL" versions - will be deprecated when fast/slow path handling done +// in the common frontend. +//---------------------------------------------------------------------------- + +// int sget_hl(int field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLSget, + art_portable_hl_sget, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +// object* sget_hl_object(int field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLSgetObject, + art_portable_hl_sget_object, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kInt32Ty)) + +// boolean sget_hl_boolean(int field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLSgetBoolean, + art_portable_hl_sget_boolean, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +// byte sget_hl_byte(int field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLSgetByte, + art_portable_hl_sget_byte, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +// char sget_hl_char(int field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLSgetChar, + art_portable_hl_sget_char, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +// char sget_hl_short(int field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLSgetShort, + art_portable_hl_sget_short, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +// char sget_hl_wide(int field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLSgetWide, + art_portable_hl_sget_wide, + kAttrReadOnly | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG1(kInt32Ty)) + +// char sget_hl_double(int field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLSgetDouble, + art_portable_hl_sget_double, + kAttrReadOnly | kAttrNoThrow, + kDoubleTy, + _EXPAND_ARG1(kInt32Ty)) + +// char sget_hl_float(int field_idx) +_EVAL_DEF_INTRINSICS_FUNC(HLSgetFloat, + art_portable_hl_sget_float, + kAttrReadOnly | kAttrNoThrow, + kFloatTy, + _EXPAND_ARG1(kInt32Ty)) +//---------------------------------------------------------------------------- +// Monitor enter/exit +//---------------------------------------------------------------------------- +// uint32_t art_portable_monitor_enter(int optFlags, JavaObject* obj) +_EVAL_DEF_INTRINSICS_FUNC(MonitorEnter, + art_portable_monitor_enter, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kJavaObjectTy)) + +// uint32_t art_portable_monitor_exit(int optFlags, JavaObject* obj) +_EVAL_DEF_INTRINSICS_FUNC(MonitorExit, + art_portable_monitor_exit, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32Ty, kJavaObjectTy)) + +//---------------------------------------------------------------------------- +// Shadow Frame +//---------------------------------------------------------------------------- + +// void art_portable_alloca_shadow_frame(int num_entry) +_EVAL_DEF_INTRINSICS_FUNC(AllocaShadowFrame, + art_portable_alloca_shadow_frame, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +// void art_portable_set_vreg(int entry_idx, ...) +_EVAL_DEF_INTRINSICS_FUNC(SetVReg, + art_portable_set_vreg, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG2(kInt32ConstantTy, kVarArgTy)) + +// void art_portable_pop_shadow_frame() +_EVAL_DEF_INTRINSICS_FUNC(PopShadowFrame, + art_portable_pop_shadow_frame, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG0()) + +// void art_portable_update_dex_pc(uint32_t dex_pc) +_EVAL_DEF_INTRINSICS_FUNC(UpdateDexPC, + art_portable_update_dex_pc, + kAttrNoThrow, + kVoidTy, + _EXPAND_ARG1(kInt32ConstantTy)) + +//---------------------------------------------------------------------------- +// FP Comparison +//---------------------------------------------------------------------------- +// int cmpl_float(float, float) +_EVAL_DEF_INTRINSICS_FUNC(CmplFloat, + art_portable_cmpl_float, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kFloatTy, kFloatTy)) + +// int cmpg_float(float, float) +_EVAL_DEF_INTRINSICS_FUNC(CmpgFloat, + art_portable_cmpg_float, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kFloatTy, kFloatTy)) + +// int cmpl_double(double, double) +_EVAL_DEF_INTRINSICS_FUNC(CmplDouble, + art_portable_cmpl_double, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kDoubleTy, kDoubleTy)) + +// int cmpg_double(double, double) +_EVAL_DEF_INTRINSICS_FUNC(CmpgDouble, + art_portable_cmpg_double, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kDoubleTy, kDoubleTy)) + +//---------------------------------------------------------------------------- +// Long Comparison +//---------------------------------------------------------------------------- +// int cmp_long(long, long) +_EVAL_DEF_INTRINSICS_FUNC(CmpLong, + art_portable_cmp_long, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kInt64Ty, kInt64Ty)) + +//---------------------------------------------------------------------------- +// Const intrinsics to assist MIR to Greenland_ir conversion. Should not materialize +// For simplicity, all use integer input +//---------------------------------------------------------------------------- +// int const_int(int) +_EVAL_DEF_INTRINSICS_FUNC(ConstInt, + art_portable_const_int, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +// JavaObject* const_obj(int) +_EVAL_DEF_INTRINSICS_FUNC(ConstObj, + art_portable_const_obj, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kInt32Ty)) + +// long const_long(long) +_EVAL_DEF_INTRINSICS_FUNC(ConstLong, + art_portable_const_long, + kAttrReadOnly | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG1(kInt64Ty)) + +// float const_float(int) +_EVAL_DEF_INTRINSICS_FUNC(ConstFloat, + art_portable_const_Float, + kAttrReadOnly | kAttrNoThrow, + kFloatTy, + _EXPAND_ARG1(kInt32Ty)) + +// double const_double(long) +_EVAL_DEF_INTRINSICS_FUNC(ConstDouble, + art_portable_const_Double, + kAttrReadOnly | kAttrNoThrow, + kDoubleTy, + _EXPAND_ARG1(kInt64Ty)) + + +//---------------------------------------------------------------------------- +// Copy intrinsics to assist MIR to Greenland_ir conversion. Should not materialize +//---------------------------------------------------------------------------- + +// void method_info(void) +_EVAL_DEF_INTRINSICS_FUNC(MethodInfo, + art_portable_method_info, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG0()) + +// int copy_int(int) +_EVAL_DEF_INTRINSICS_FUNC(CopyInt, + art_portable_copy_int, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +// JavaObject* copy_obj(obj) +_EVAL_DEF_INTRINSICS_FUNC(CopyObj, + art_portable_copy_obj, + kAttrReadOnly | kAttrNoThrow, + kJavaObjectTy, + _EXPAND_ARG1(kJavaObjectTy)) + +// long copy_long(long) +_EVAL_DEF_INTRINSICS_FUNC(CopyLong, + art_portable_copy_long, + kAttrReadOnly | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG1(kInt64Ty)) + +// float copy_float(float) +_EVAL_DEF_INTRINSICS_FUNC(CopyFloat, + art_portable_copy_Float, + kAttrReadOnly | kAttrNoThrow, + kFloatTy, + _EXPAND_ARG1(kFloatTy)) + +// double copy_double(double) +_EVAL_DEF_INTRINSICS_FUNC(CopyDouble, + art_portable_copy_Double, + kAttrReadOnly | kAttrNoThrow, + kDoubleTy, + _EXPAND_ARG1(kDoubleTy)) + +//---------------------------------------------------------------------------- +// Shift intrinsics. Shift semantics for Dalvik are a bit different than +// the llvm shift operators. For 32-bit shifts, the shift count is constrained +// to the range of 0..31, while for 64-bit shifts we limit to 0..63. +// Further, the shift count for Long shifts in Dalvik is 32 bits, while +// llvm requires a 64-bit shift count. For GBC, we represent shifts as an +// intrinsic to allow most efficient target-dependent lowering. +//---------------------------------------------------------------------------- +// long shl_long(long,int) +_EVAL_DEF_INTRINSICS_FUNC(SHLLong, + art_portable_shl_long, + kAttrReadOnly | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG2(kInt64Ty,kInt32Ty)) +// long shr_long(long,int) +_EVAL_DEF_INTRINSICS_FUNC(SHRLong, + art_portable_shr_long, + kAttrReadOnly | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG2(kInt64Ty,kInt32Ty)) +// long ushr_long(long,int) +_EVAL_DEF_INTRINSICS_FUNC(USHRLong, + art_portable_ushl_long, + kAttrReadOnly | kAttrNoThrow, + kInt64Ty, + _EXPAND_ARG2(kInt64Ty,kInt32Ty)) +// int shl_int(int,int) +_EVAL_DEF_INTRINSICS_FUNC(SHLInt, + art_portable_shl_int, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kInt32Ty,kInt32Ty)) +// long shr_int(int,int) +_EVAL_DEF_INTRINSICS_FUNC(SHRInt, + art_portable_shr_int, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kInt32Ty,kInt32Ty)) +// int ushr_long(int,int) +_EVAL_DEF_INTRINSICS_FUNC(USHRInt, + art_portable_ushl_int, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG2(kInt32Ty,kInt32Ty)) +//---------------------------------------------------------------------------- +// Conversion instrinsics. Note: these should eventually be removed. We +// can express these directly in bitcode, but by using intrinsics the +// Quick compiler can be more efficient. Some extra optimization infrastructure +// will have to be developed to undo the bitcode verbosity when these are +// done inline. +//---------------------------------------------------------------------------- +// int int_to_byte(int) +_EVAL_DEF_INTRINSICS_FUNC(IntToByte, + art_portable_int_to_byte, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +// int int_to_char(int) +_EVAL_DEF_INTRINSICS_FUNC(IntToChar, + art_portable_int_to_char, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +// int int_to_short(int) +_EVAL_DEF_INTRINSICS_FUNC(IntToShort, + art_portable_int_to_short, + kAttrReadOnly | kAttrNoThrow, + kInt32Ty, + _EXPAND_ARG1(kInt32Ty)) + +//---------------------------------------------------------------------------- +// Memory barrier +//---------------------------------------------------------------------------- +// void constructor_barrier() +_EVAL_DEF_INTRINSICS_FUNC(ConstructorBarrier, + art_portable_constructor_barrier, + kAttrReadOnly | kAttrNoThrow, + kVoidTy, + _EXPAND_ARG0()) + +// Clean up all internal used macros +#undef _EXPAND_ARG0 +#undef _EXPAND_ARG1 +#undef _EXPAND_ARG2 +#undef _EXPAND_ARG3 +#undef _EXPAND_ARG4 +#undef _EXPAND_ARG5 + +#undef _JTYPE_OF_kInt1Ty_UNDER_kArray +#undef _JTYPE_OF_kInt8Ty_UNDER_kArray +#undef _JTYPE_OF_kInt16Ty_UNDER_kArray +#undef _JTYPE_OF_kInt32Ty_UNDER_kArray +#undef _JTYPE_OF_kInt64Ty_UNDER_kArray +#undef _JTYPE_OF_kJavaObjectTy_UNDER_kArray + +#undef _JTYPE_OF_kInt1Ty_UNDER_kField +#undef _JTYPE_OF_kInt8Ty_UNDER_kField +#undef _JTYPE_OF_kInt16Ty_UNDER_kField +#undef _JTYPE_OF_kInt32Ty_UNDER_kField +#undef _JTYPE_OF_kInt64Ty_UNDER_kField +#undef _JTYPE_OF_kJavaObjectTy_UNDER_kField + +#undef DEF_INTRINSICS_FUNC diff --git a/compiler/llvm/intrinsic_helper.cc b/compiler/llvm/intrinsic_helper.cc new file mode 100644 index 0000000000..a34cb330bc --- /dev/null +++ b/compiler/llvm/intrinsic_helper.cc @@ -0,0 +1,178 @@ +/* + * 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 "intrinsic_helper.h" + +#include "ir_builder.h" + +#include <llvm/IR/Attributes.h> +#include <llvm/IR/DerivedTypes.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/IRBuilder.h> +#include <llvm/IR/Intrinsics.h> + +namespace art { +namespace llvm { + +const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[] = { +#define DEF_INTRINSICS_FUNC(_, NAME, ATTR, RET_TYPE, ARG1_TYPE, ARG2_TYPE, \ + ARG3_TYPE, ARG4_TYPE, \ + ARG5_TYPE) \ + { #NAME, ATTR, RET_TYPE, { ARG1_TYPE, ARG2_TYPE, \ + ARG3_TYPE, ARG4_TYPE, \ + ARG5_TYPE} }, +#include "intrinsic_func_list.def" +}; + +static ::llvm::Type* GetLLVMTypeOfIntrinsicValType(IRBuilder& irb, + IntrinsicHelper::IntrinsicValType type) { + switch (type) { + case IntrinsicHelper::kVoidTy: { + return irb.getVoidTy(); + } + case IntrinsicHelper::kJavaObjectTy: { + return irb.getJObjectTy(); + } + case IntrinsicHelper::kJavaMethodTy: { + return irb.getJMethodTy(); + } + case IntrinsicHelper::kJavaThreadTy: { + return irb.getJThreadTy(); + } + case IntrinsicHelper::kInt1Ty: + case IntrinsicHelper::kInt1ConstantTy: { + return irb.getInt1Ty(); + } + case IntrinsicHelper::kInt8Ty: + case IntrinsicHelper::kInt8ConstantTy: { + return irb.getInt8Ty(); + } + case IntrinsicHelper::kInt16Ty: + case IntrinsicHelper::kInt16ConstantTy: { + return irb.getInt16Ty(); + } + case IntrinsicHelper::kInt32Ty: + case IntrinsicHelper::kInt32ConstantTy: { + return irb.getInt32Ty(); + } + case IntrinsicHelper::kInt64Ty: + case IntrinsicHelper::kInt64ConstantTy: { + return irb.getInt64Ty(); + } + case IntrinsicHelper::kFloatTy: + case IntrinsicHelper::kFloatConstantTy: { + return irb.getFloatTy(); + } + case IntrinsicHelper::kDoubleTy: + case IntrinsicHelper::kDoubleConstantTy: { + return irb.getDoubleTy(); + } + case IntrinsicHelper::kNone: + case IntrinsicHelper::kVarArgTy: + default: { + LOG(FATAL) << "Invalid intrinsic type " << type << "to get LLVM type!"; + return NULL; + } + } + // unreachable +} + +IntrinsicHelper::IntrinsicHelper(::llvm::LLVMContext& context, + ::llvm::Module& module) { + IRBuilder irb(context, module, *this); + + ::memset(intrinsic_funcs_, 0, sizeof(intrinsic_funcs_)); + + // This loop does the following things: + // 1. Introduce the intrinsic function into the module + // 2. Add "nocapture" and "noalias" attribute to the arguments in all + // intrinsics functions. + // 3. Initialize intrinsic_funcs_map_. + for (unsigned i = 0; i < MaxIntrinsicId; i++) { + IntrinsicId id = static_cast<IntrinsicId>(i); + const IntrinsicInfo& info = Info[i]; + + // Parse and construct the argument type from IntrinsicInfo + ::llvm::Type* arg_type[kIntrinsicMaxArgc]; + unsigned num_args = 0; + bool is_var_arg = false; + for (unsigned arg_iter = 0; arg_iter < kIntrinsicMaxArgc; arg_iter++) { + IntrinsicValType type = info.arg_type_[arg_iter]; + + if (type == kNone) { + break; + } else if (type == kVarArgTy) { + // Variable argument type must be the last argument + is_var_arg = true; + break; + } + + arg_type[num_args++] = GetLLVMTypeOfIntrinsicValType(irb, type); + } + + // Construct the function type + ::llvm::Type* ret_type = + GetLLVMTypeOfIntrinsicValType(irb, info.ret_val_type_); + + ::llvm::FunctionType* type = + ::llvm::FunctionType::get(ret_type, + ::llvm::ArrayRef< ::llvm::Type*>(arg_type, num_args), + is_var_arg); + + // Declare the function + ::llvm::Function *fn = ::llvm::Function::Create(type, + ::llvm::Function::ExternalLinkage, + info.name_, &module); + + if (info.attr_ & kAttrReadOnly) { + fn->setOnlyReadsMemory(); + } + if (info.attr_ & kAttrReadNone) { + fn->setDoesNotAccessMemory(); + } + // None of the intrinsics throws exception + fn->setDoesNotThrow(); + + intrinsic_funcs_[id] = fn; + + DCHECK_NE(fn, static_cast< ::llvm::Function*>(NULL)) << "Intrinsic `" + << GetName(id) << "' was not defined!"; + + // Add "noalias" and "nocapture" attribute to all arguments of pointer type + for (::llvm::Function::arg_iterator arg_iter = fn->arg_begin(), + arg_end = fn->arg_end(); arg_iter != arg_end; arg_iter++) { + if (arg_iter->getType()->isPointerTy()) { + std::vector< ::llvm::Attribute::AttrKind> attributes; + attributes.push_back(::llvm::Attribute::NoCapture); + attributes.push_back(::llvm::Attribute::NoAlias); + ::llvm::AttributeSet attribute_set = ::llvm::AttributeSet::get(fn->getContext(), + arg_iter->getArgNo(), + attributes); + arg_iter->addAttr(attribute_set); + } + } + + // Insert the newly created intrinsic to intrinsic_funcs_map_ + if (!intrinsic_funcs_map_.insert(std::make_pair(fn, id)).second) { + LOG(FATAL) << "Duplicate entry in intrinsic functions map?"; + } + } + + return; +} + +} // namespace llvm +} // namespace art diff --git a/compiler/llvm/intrinsic_helper.h b/compiler/llvm/intrinsic_helper.h new file mode 100644 index 0000000000..49b8a95230 --- /dev/null +++ b/compiler/llvm/intrinsic_helper.h @@ -0,0 +1,157 @@ +/* + * 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_SRC_GREENLAND_INTRINSIC_HELPER_H_ +#define ART_SRC_GREENLAND_INTRINSIC_HELPER_H_ + +#include "base/logging.h" + +#include <llvm/ADT/DenseMap.h> + +namespace llvm { + class Function; + class FunctionType; + class LLVMContext; + class Module; +} // namespace llvm + +namespace art { +namespace llvm { + +class IRBuilder; + +class IntrinsicHelper { + public: + enum IntrinsicId { +#define DEF_INTRINSICS_FUNC(ID, ...) ID, +#include "intrinsic_func_list.def" + MaxIntrinsicId, + + // Pseudo-intrinsics Id + UnknownId + }; + + enum IntrinsicAttribute { + kAttrNone = 0, + + // Intrinsic that neither modified the memory state nor refer to the global + // state + kAttrReadNone = 1 << 0, + + // Intrinsic that doesn't modify the memory state. Note that one should set + // this flag carefully when the intrinsic may throw exception. Since the + // thread state is implicitly modified when an exception is thrown. + kAttrReadOnly = 1 << 1, + + // Note that intrinsic without kAttrNoThrow and kAttrDoThrow set means that + // intrinsic generates exception in some cases + + // Intrinsic that never generates exception + kAttrNoThrow = 1 << 2, + // Intrinsic that always generate exception + kAttrDoThrow = 1 << 3, + }; + + enum IntrinsicValType { + kNone, + + kVoidTy, + + kJavaObjectTy, + kJavaMethodTy, + kJavaThreadTy, + + kInt1Ty, + kInt8Ty, + kInt16Ty, + kInt32Ty, + kInt64Ty, + kFloatTy, + kDoubleTy, + + kInt1ConstantTy, + kInt8ConstantTy, + kInt16ConstantTy, + kInt32ConstantTy, + kInt64ConstantTy, + kFloatConstantTy, + kDoubleConstantTy, + + kVarArgTy, + }; + + enum { + kIntrinsicMaxArgc = 5 + }; + + typedef struct IntrinsicInfo { + const char* name_; + unsigned attr_; + IntrinsicValType ret_val_type_; + IntrinsicValType arg_type_[kIntrinsicMaxArgc]; + } IntrinsicInfo; + + private: + static const IntrinsicInfo Info[]; + + public: + static const IntrinsicInfo& GetInfo(IntrinsicId id) { + DCHECK(id >= 0 && id < MaxIntrinsicId) << "Unknown ART intrinsics ID: " + << id; + return Info[id]; + } + + static const char* GetName(IntrinsicId id) { + return (id <= MaxIntrinsicId) ? GetInfo(id).name_ : "InvalidIntrinsic"; + } + + static unsigned GetAttr(IntrinsicId id) { + return GetInfo(id).attr_; + } + + public: + IntrinsicHelper(::llvm::LLVMContext& context, ::llvm::Module& module); + + ::llvm::Function* GetIntrinsicFunction(IntrinsicId id) { + DCHECK(id >= 0 && id < MaxIntrinsicId) << "Unknown ART intrinsics ID: " + << id; + return intrinsic_funcs_[id]; + } + + IntrinsicId GetIntrinsicId(const ::llvm::Function* func) const { + ::llvm::DenseMap<const ::llvm::Function*, IntrinsicId>::const_iterator + i = intrinsic_funcs_map_.find(func); + if (i == intrinsic_funcs_map_.end()) { + return UnknownId; + } else { + return i->second; + } + } + + private: + // FIXME: "+1" is to workaround the GCC bugs: + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949 + // Remove this when uses newer GCC (> 4.4.3) + ::llvm::Function* intrinsic_funcs_[MaxIntrinsicId + 1]; + + // Map a llvm::Function to its intrinsic id + ::llvm::DenseMap<const ::llvm::Function*, IntrinsicId> intrinsic_funcs_map_; +}; + +} // namespace llvm +} // namespace art + +#endif // ART_SRC_GREENLAND_INTRINSIC_HELPER_H_ diff --git a/compiler/llvm/ir_builder.cc b/compiler/llvm/ir_builder.cc new file mode 100644 index 0000000000..a65cf2bdae --- /dev/null +++ b/compiler/llvm/ir_builder.cc @@ -0,0 +1,130 @@ +/* + * 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 "ir_builder.h" + +#include "base/stringprintf.h" + +#include <llvm/IR/Module.h> + +namespace art { +namespace llvm { + + +//---------------------------------------------------------------------------- +// General +//---------------------------------------------------------------------------- + +IRBuilder::IRBuilder(::llvm::LLVMContext& context, ::llvm::Module& module, + IntrinsicHelper& intrinsic_helper) + : LLVMIRBuilder(context), module_(&module), mdb_(context), java_object_type_(NULL), + java_method_type_(NULL), java_thread_type_(NULL), intrinsic_helper_(intrinsic_helper) { + // Get java object type from module + ::llvm::Type* jobject_struct_type = module.getTypeByName("JavaObject"); + CHECK(jobject_struct_type != NULL); + java_object_type_ = jobject_struct_type->getPointerTo(); + + // If type of Method is not explicitly defined in the module, use JavaObject* + ::llvm::Type* type = module.getTypeByName("Method"); + if (type != NULL) { + java_method_type_ = type->getPointerTo(); + } else { + java_method_type_ = java_object_type_; + } + + // If type of Thread is not explicitly defined in the module, use JavaObject* + type = module.getTypeByName("Thread"); + if (type != NULL) { + java_thread_type_ = type->getPointerTo(); + } else { + java_thread_type_ = java_object_type_; + } + + // Create JEnv* type + ::llvm::Type* jenv_struct_type = ::llvm::StructType::create(context, "JEnv"); + jenv_type_ = jenv_struct_type->getPointerTo(); + + // Get Art shadow frame struct type from module + art_frame_type_ = module.getTypeByName("ShadowFrame"); + CHECK(art_frame_type_ != NULL); + + runtime_support_ = NULL; +} + + +//---------------------------------------------------------------------------- +// Type Helper Function +//---------------------------------------------------------------------------- + +::llvm::Type* IRBuilder::getJType(JType jty) { + switch (jty) { + case kVoid: + return getJVoidTy(); + + case kBoolean: + return getJBooleanTy(); + + case kByte: + return getJByteTy(); + + case kChar: + return getJCharTy(); + + case kShort: + return getJShortTy(); + + case kInt: + return getJIntTy(); + + case kLong: + return getJLongTy(); + + case kFloat: + return getJFloatTy(); + + case kDouble: + return getJDoubleTy(); + + case kObject: + return getJObjectTy(); + + default: + LOG(FATAL) << "Unknown java type: " << jty; + return NULL; + } +} + +::llvm::StructType* IRBuilder::getShadowFrameTy(uint32_t vreg_size) { + std::string name(StringPrintf("ShadowFrame%u", vreg_size)); + + // Try to find the existing struct type definition + if (::llvm::Type* type = module_->getTypeByName(name)) { + CHECK(::llvm::isa< ::llvm::StructType>(type)); + return static_cast< ::llvm::StructType*>(type); + } + + // Create new struct type definition + ::llvm::Type* elem_types[] = { + art_frame_type_, + ::llvm::ArrayType::get(getInt32Ty(), vreg_size), + }; + + return ::llvm::StructType::create(elem_types, name); +} + + +} // namespace llvm +} // namespace art diff --git a/compiler/llvm/ir_builder.h b/compiler/llvm/ir_builder.h new file mode 100644 index 0000000000..734b22f791 --- /dev/null +++ b/compiler/llvm/ir_builder.h @@ -0,0 +1,490 @@ +/* + * 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_SRC_COMPILER_LLVM_IR_BUILDER_H_ +#define ART_SRC_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_SRC_COMPILER_LLVM_IR_BUILDER_H_ diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc new file mode 100644 index 0000000000..dfb572477e --- /dev/null +++ b/compiler/llvm/llvm_compilation_unit.cc @@ -0,0 +1,343 @@ +/* + * 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. + */ + +// TODO: TargetLibraryInfo is included before sys/... because on Android bionic does #define tricks like: +// +// #define stat64 stat +// #define fstat64 fstat +// #define lstat64 lstat +// +// which causes grief. bionic probably should not do that. +#include <llvm/Target/TargetLibraryInfo.h> + +#include "llvm_compilation_unit.h" + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <string> + +#include <llvm/ADT/OwningPtr.h> +#include <llvm/ADT/StringSet.h> +#include <llvm/ADT/Triple.h> +#include <llvm/Analysis/CallGraph.h> +#include <llvm/Analysis/CallGraphSCCPass.h> +#include <llvm/Analysis/Dominators.h> +#include <llvm/Analysis/LoopInfo.h> +#include <llvm/Analysis/LoopPass.h> +#include <llvm/Analysis/RegionPass.h> +#include <llvm/Analysis/ScalarEvolution.h> +#include <llvm/Analysis/Verifier.h> +#include <llvm/Assembly/PrintModulePass.h> +#include <llvm/Bitcode/ReaderWriter.h> +#include <llvm/CodeGen/MachineFrameInfo.h> +#include <llvm/CodeGen/MachineFunction.h> +#include <llvm/CodeGen/MachineFunctionPass.h> +#include <llvm/DebugInfo.h> +#include <llvm/IR/DataLayout.h> +#include <llvm/IR/DerivedTypes.h> +#include <llvm/IR/LLVMContext.h> +#include <llvm/IR/Module.h> +#include <llvm/Object/ObjectFile.h> +#include <llvm/PassManager.h> +#include <llvm/Support/Debug.h> +#include <llvm/Support/ELF.h> +#include <llvm/Support/FormattedStream.h> +#include <llvm/Support/ManagedStatic.h> +#include <llvm/Support/MemoryBuffer.h> +#include <llvm/Support/PassNameParser.h> +#include <llvm/Support/PluginLoader.h> +#include <llvm/Support/PrettyStackTrace.h> +#include <llvm/Support/Signals.h> +#include <llvm/Support/SystemUtils.h> +#include <llvm/Support/TargetRegistry.h> +#include <llvm/Support/TargetSelect.h> +#include <llvm/Support/ToolOutputFile.h> +#include <llvm/Support/raw_ostream.h> +#include <llvm/Support/system_error.h> +#include <llvm/Target/TargetMachine.h> +#include <llvm/Transforms/IPO.h> +#include <llvm/Transforms/IPO/PassManagerBuilder.h> +#include <llvm/Transforms/Scalar.h> + +#include "base/logging.h" +#include "base/unix_file/fd_file.h" +#include "compiled_method.h" +#include "compiler_llvm.h" +#include "instruction_set.h" +#include "ir_builder.h" +#include "os.h" +#include "runtime_support_builder_arm.h" +#include "runtime_support_builder_thumb2.h" +#include "runtime_support_builder_x86.h" +#include "utils_llvm.h" + +namespace art { +namespace llvm { + +::llvm::FunctionPass* +CreateGBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb, + CompilerDriver* compiler, const DexCompilationUnit* dex_compilation_unit); + +::llvm::Module* makeLLVMModuleContents(::llvm::Module* module); + + +LlvmCompilationUnit::LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, size_t cunit_id) + : compiler_llvm_(compiler_llvm), cunit_id_(cunit_id) { + driver_ = NULL; + dex_compilation_unit_ = NULL; + llvm_info_.reset(new LLVMInfo()); + context_.reset(llvm_info_->GetLLVMContext()); + module_ = llvm_info_->GetLLVMModule(); + + // Include the runtime function declaration + makeLLVMModuleContents(module_); + + + intrinsic_helper_.reset(new IntrinsicHelper(*context_, *module_)); + + // Create IRBuilder + irb_.reset(new IRBuilder(*context_, *module_, *intrinsic_helper_)); + + // We always need a switch case, so just use a normal function. + switch(GetInstructionSet()) { + default: + runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_)); + break; + case kArm: + runtime_support_.reset(new RuntimeSupportBuilderARM(*context_, *module_, *irb_)); + break; + case kThumb2: + runtime_support_.reset(new RuntimeSupportBuilderThumb2(*context_, *module_, *irb_)); + break; + case kX86: + runtime_support_.reset(new RuntimeSupportBuilderX86(*context_, *module_, *irb_)); + break; + } + + irb_->SetRuntimeSupport(runtime_support_.get()); +} + + +LlvmCompilationUnit::~LlvmCompilationUnit() { + ::llvm::LLVMContext* llvm_context = context_.release(); // Managed by llvm_info_ + CHECK(llvm_context != NULL); +} + + +InstructionSet LlvmCompilationUnit::GetInstructionSet() const { + return compiler_llvm_->GetInstructionSet(); +} + + +static std::string DumpDirectory() { + if (kIsTargetBuild) { + return GetDalvikCacheOrDie(GetAndroidData()); + } + return "/tmp"; +} + +void LlvmCompilationUnit::DumpBitcodeToFile() { + std::string bitcode; + DumpBitcodeToString(bitcode); + std::string filename(StringPrintf("%s/Art%u.bc", DumpDirectory().c_str(), cunit_id_)); + UniquePtr<File> output(OS::OpenFile(filename.c_str(), true)); + output->WriteFully(bitcode.data(), bitcode.size()); + LOG(INFO) << ".bc file written successfully: " << filename; +} + +void LlvmCompilationUnit::DumpBitcodeToString(std::string& str_buffer) { + ::llvm::raw_string_ostream str_os(str_buffer); + ::llvm::WriteBitcodeToFile(module_, str_os); +} + +bool LlvmCompilationUnit::Materialize() { + + const bool kDumpBitcode = false; + if (kDumpBitcode) { + // Dump the bitcode for debugging + DumpBitcodeToFile(); + } + + // Compile and prelink ::llvm::Module + if (!MaterializeToString(elf_object_)) { + LOG(ERROR) << "Failed to materialize compilation unit " << cunit_id_; + return false; + } + + const bool kDumpELF = false; + if (kDumpELF) { + // Dump the ELF image for debugging + std::string filename(StringPrintf("%s/Art%u.o", DumpDirectory().c_str(), cunit_id_)); + UniquePtr<File> output(OS::OpenFile(filename.c_str(), true)); + output->WriteFully(elf_object_.data(), elf_object_.size()); + LOG(INFO) << ".o file written successfully: " << filename; + } + + return true; +} + + +bool LlvmCompilationUnit::MaterializeToString(std::string& str_buffer) { + ::llvm::raw_string_ostream str_os(str_buffer); + return MaterializeToRawOStream(str_os); +} + + +bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_stream) { + // Lookup the LLVM target + std::string target_triple; + std::string target_cpu; + std::string target_attr; + CompilerDriver::InstructionSetToLLVMTarget(GetInstructionSet(), target_triple, target_cpu, target_attr); + + std::string errmsg; + const ::llvm::Target* target = + ::llvm::TargetRegistry::lookupTarget(target_triple, errmsg); + + CHECK(target != NULL) << errmsg; + + // Target options + ::llvm::TargetOptions target_options; + target_options.FloatABIType = ::llvm::FloatABI::Soft; + target_options.NoFramePointerElim = true; + target_options.NoFramePointerElimNonLeaf = true; + target_options.UseSoftFloat = false; + target_options.EnableFastISel = false; + + // Create the ::llvm::TargetMachine + ::llvm::OwningPtr< ::llvm::TargetMachine> target_machine( + target->createTargetMachine(target_triple, target_cpu, target_attr, target_options, + ::llvm::Reloc::Static, ::llvm::CodeModel::Small, + ::llvm::CodeGenOpt::Aggressive)); + + CHECK(target_machine.get() != NULL) << "Failed to create target machine"; + + // Add target data + const ::llvm::DataLayout* data_layout = target_machine->getDataLayout(); + + // PassManager for code generation passes + ::llvm::PassManager pm; + pm.add(new ::llvm::DataLayout(*data_layout)); + + // FunctionPassManager for optimization pass + ::llvm::FunctionPassManager fpm(module_); + fpm.add(new ::llvm::DataLayout(*data_layout)); + + if (bitcode_filename_.empty()) { + // If we don't need write the bitcode to file, add the AddSuspendCheckToLoopLatchPass to the + // regular FunctionPass. + fpm.add(CreateGBCExpanderPass(*llvm_info_->GetIntrinsicHelper(), *irb_.get(), + driver_, dex_compilation_unit_)); + } else { + ::llvm::FunctionPassManager fpm2(module_); + fpm2.add(CreateGBCExpanderPass(*llvm_info_->GetIntrinsicHelper(), *irb_.get(), + driver_, dex_compilation_unit_)); + fpm2.doInitialization(); + for (::llvm::Module::iterator F = module_->begin(), E = module_->end(); + F != E; ++F) { + fpm2.run(*F); + } + fpm2.doFinalization(); + + // Write bitcode to file + std::string errmsg; + + ::llvm::OwningPtr< ::llvm::tool_output_file> out_file( + new ::llvm::tool_output_file(bitcode_filename_.c_str(), errmsg, + ::llvm::raw_fd_ostream::F_Binary)); + + + if (!errmsg.empty()) { + LOG(ERROR) << "Failed to create bitcode output file: " << errmsg; + return false; + } + + ::llvm::WriteBitcodeToFile(module_, out_file->os()); + out_file->keep(); + } + + // Add optimization pass + ::llvm::PassManagerBuilder pm_builder; + // TODO: Use inliner after we can do IPO. + pm_builder.Inliner = NULL; + //pm_builder.Inliner = ::llvm::createFunctionInliningPass(); + //pm_builder.Inliner = ::llvm::createAlwaysInlinerPass(); + //pm_builder.Inliner = ::llvm::createPartialInliningPass(); + pm_builder.OptLevel = 3; + pm_builder.DisableSimplifyLibCalls = 1; + pm_builder.DisableUnitAtATime = 1; + pm_builder.populateFunctionPassManager(fpm); + pm_builder.populateModulePassManager(pm); + pm.add(::llvm::createStripDeadPrototypesPass()); + + // Add passes to emit ELF image + { + ::llvm::formatted_raw_ostream formatted_os(out_stream, false); + + // Ask the target to add backend passes as necessary. + if (target_machine->addPassesToEmitFile(pm, + formatted_os, + ::llvm::TargetMachine::CGFT_ObjectFile, + true)) { + LOG(FATAL) << "Unable to generate ELF for this target"; + return false; + } + + // Run the per-function optimization + fpm.doInitialization(); + for (::llvm::Module::iterator F = module_->begin(), E = module_->end(); + F != E; ++F) { + fpm.run(*F); + } + fpm.doFinalization(); + + // Run the code generation passes + pm.run(*module_); + } + + return true; +} + +// Check whether the align is less than or equal to the code alignment of +// that architecture. Since the Oat writer only guarantee that the compiled +// method being aligned to kArchAlignment, we have no way to align the ELf +// section if the section alignment is greater than kArchAlignment. +void LlvmCompilationUnit::CheckCodeAlign(uint32_t align) const { + InstructionSet insn_set = GetInstructionSet(); + switch (insn_set) { + case kThumb2: + case kArm: + CHECK_LE(align, static_cast<uint32_t>(kArmAlignment)); + break; + + case kX86: + CHECK_LE(align, static_cast<uint32_t>(kX86Alignment)); + break; + + case kMips: + CHECK_LE(align, static_cast<uint32_t>(kMipsAlignment)); + break; + + default: + LOG(FATAL) << "Unknown instruction set: " << insn_set; + } +} + + +} // namespace llvm +} // namespace art diff --git a/compiler/llvm/llvm_compilation_unit.h b/compiler/llvm/llvm_compilation_unit.h new file mode 100644 index 0000000000..a4f0adbab8 --- /dev/null +++ b/compiler/llvm/llvm_compilation_unit.h @@ -0,0 +1,138 @@ +/* + * 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_SRC_COMPILER_LLVM_LLVM_COMPILATION_UNIT_H_ +#define ART_SRC_COMPILER_LLVM_LLVM_COMPILATION_UNIT_H_ + +#include "base/logging.h" +#include "base/mutex.h" +#include "dex/compiler_internals.h" +#include "driver/compiler_driver.h" +#include "driver/dex_compilation_unit.h" +#include "globals.h" +#include "instruction_set.h" +#include "runtime_support_builder.h" +#include "runtime_support_llvm_func.h" +#include "safe_map.h" + +#include <UniquePtr.h> +#include <string> +#include <vector> + +namespace art { + class CompiledMethod; +} + +namespace llvm { + class Function; + class LLVMContext; + class Module; + class raw_ostream; +} + +namespace art { +namespace llvm { + +class CompilerLLVM; +class IRBuilder; + +class LlvmCompilationUnit { + public: + ~LlvmCompilationUnit(); + + uint32_t GetCompilationUnitId() const { + return cunit_id_; + } + + InstructionSet GetInstructionSet() const; + + ::llvm::LLVMContext* GetLLVMContext() const { + return context_.get(); + } + + ::llvm::Module* GetModule() const { + return module_; + } + + IRBuilder* GetIRBuilder() const { + return irb_.get(); + } + + void SetBitcodeFileName(const std::string& bitcode_filename) { + bitcode_filename_ = bitcode_filename; + } + + LLVMInfo* GetQuickContext() const { + return llvm_info_.get(); + } + void SetCompilerDriver(CompilerDriver* driver) { + driver_ = driver; + } + DexCompilationUnit* GetDexCompilationUnit() { + return dex_compilation_unit_; + } + void SetDexCompilationUnit(DexCompilationUnit* dex_compilation_unit) { + dex_compilation_unit_ = dex_compilation_unit; + } + + bool Materialize(); + + bool IsMaterialized() const { + return !elf_object_.empty(); + } + + const std::string& GetElfObject() const { + DCHECK(IsMaterialized()); + return elf_object_; + } + + private: + LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, + uint32_t cunit_id); + + const CompilerLLVM* compiler_llvm_; + const uint32_t cunit_id_; + + UniquePtr< ::llvm::LLVMContext> context_; + UniquePtr<IRBuilder> irb_; + UniquePtr<RuntimeSupportBuilder> runtime_support_; + ::llvm::Module* module_; // Managed by context_ + UniquePtr<IntrinsicHelper> intrinsic_helper_; + UniquePtr<LLVMInfo> llvm_info_; + CompilerDriver* driver_; + DexCompilationUnit* dex_compilation_unit_; + + std::string bitcode_filename_; + + std::string elf_object_; + + SafeMap<const ::llvm::Function*, CompiledMethod*> compiled_methods_map_; + + void CheckCodeAlign(uint32_t offset) const; + + void DumpBitcodeToFile(); + void DumpBitcodeToString(std::string& str_buffer); + + bool MaterializeToString(std::string& str_buffer); + bool MaterializeToRawOStream(::llvm::raw_ostream& out_stream); + + friend class CompilerLLVM; // For LlvmCompilationUnit constructor +}; + +} // namespace llvm +} // namespace art + +#endif // ART_SRC_COMPILER_LLVM_LLVM_COMPILATION_UNIT_H_ diff --git a/compiler/llvm/md_builder.cc b/compiler/llvm/md_builder.cc new file mode 100644 index 0000000000..3884f51056 --- /dev/null +++ b/compiler/llvm/md_builder.cc @@ -0,0 +1,101 @@ +/* + * 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 "md_builder.h" + +#include "llvm/IR/MDBuilder.h" + +#include <string> + +namespace art { +namespace llvm { + + +::llvm::MDNode* MDBuilder::GetTBAASpecialType(TBAASpecialType sty_id) { + DCHECK_GE(sty_id, 0) << "Unknown TBAA special type: " << sty_id; + DCHECK_LT(sty_id, MAX_TBAA_SPECIAL_TYPE) << "Unknown TBAA special type: " << sty_id; + DCHECK(tbaa_root_ != NULL); + + ::llvm::MDNode*& spec_ty = tbaa_special_type_[sty_id]; + if (spec_ty == NULL) { + switch (sty_id) { + case kTBAARegister: spec_ty = createTBAANode("Register", tbaa_root_); break; + case kTBAAStackTemp: spec_ty = createTBAANode("StackTemp", tbaa_root_); break; + case kTBAAHeapArray: spec_ty = createTBAANode("HeapArray", tbaa_root_); break; + case kTBAAHeapInstance: spec_ty = createTBAANode("HeapInstance", tbaa_root_); break; + case kTBAAHeapStatic: spec_ty = createTBAANode("HeapStatic", tbaa_root_); break; + case kTBAAJRuntime: spec_ty = createTBAANode("JRuntime", tbaa_root_); break; + case kTBAARuntimeInfo: spec_ty = createTBAANode("RuntimeInfo", + GetTBAASpecialType(kTBAAJRuntime)); break; + case kTBAAShadowFrame: spec_ty = createTBAANode("ShadowFrame", + GetTBAASpecialType(kTBAAJRuntime)); break; + case kTBAAConstJObject: spec_ty = createTBAANode("ConstJObject", tbaa_root_, true); break; + default: + LOG(FATAL) << "Unknown TBAA special type: " << sty_id; + break; + } + } + return spec_ty; +} + +::llvm::MDNode* MDBuilder::GetTBAAMemoryJType(TBAASpecialType sty_id, JType jty_id) { + DCHECK(sty_id == kTBAAHeapArray || + sty_id == kTBAAHeapInstance || + sty_id == kTBAAHeapStatic) << "SpecialType must be array, instance, or static"; + + DCHECK_GE(jty_id, 0) << "Unknown JType: " << jty_id; + DCHECK_LT(jty_id, MAX_JTYPE) << "Unknown JType: " << jty_id; + DCHECK_NE(jty_id, kVoid) << "Can't load/store Void type!"; + + std::string name; + size_t sty_mapped_index = 0; + switch (sty_id) { + case kTBAAHeapArray: sty_mapped_index = 0; name = "HeapArray "; break; + case kTBAAHeapInstance: sty_mapped_index = 1; name = "HeapInstance "; break; + case kTBAAHeapStatic: sty_mapped_index = 2; name = "HeapStatic "; break; + default: + LOG(FATAL) << "Unknown TBAA special type: " << sty_id; + break; + } + + ::llvm::MDNode*& spec_ty = tbaa_memory_jtype_[sty_mapped_index][jty_id]; + if (spec_ty != NULL) { + return spec_ty; + } + + switch (jty_id) { + case kBoolean: name += "Boolean"; break; + case kByte: name += "Byte"; break; + case kChar: name += "Char"; break; + case kShort: name += "Short"; break; + case kInt: name += "Int"; break; + case kLong: name += "Long"; break; + case kFloat: name += "Float"; break; + case kDouble: name += "Double"; break; + case kObject: name += "Object"; break; + default: + LOG(FATAL) << "Unknown JType: " << jty_id; + break; + } + + spec_ty = createTBAANode(name, GetTBAASpecialType(sty_id)); + return spec_ty; +} + + +} // namespace llvm +} // namespace art diff --git a/compiler/llvm/md_builder.h b/compiler/llvm/md_builder.h new file mode 100644 index 0000000000..79a7caa04c --- /dev/null +++ b/compiler/llvm/md_builder.h @@ -0,0 +1,71 @@ +/* + * 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_SRC_COMPILER_LLVM_MD_BUILDER_H_ +#define ART_SRC_COMPILER_LLVM_MD_BUILDER_H_ + +#include "backend_types.h" + +#include "llvm/IR/MDBuilder.h" + +#include <cstring> + +namespace llvm { + class LLVMContext; + class MDNode; +} + +namespace art { +namespace llvm { + +typedef ::llvm::MDBuilder LLVMMDBuilder; + +class MDBuilder : public LLVMMDBuilder { + public: + MDBuilder(::llvm::LLVMContext& context) + : LLVMMDBuilder(context), tbaa_root_(createTBAARoot("Art TBAA Root")) { + std::memset(tbaa_special_type_, 0, sizeof(tbaa_special_type_)); + std::memset(tbaa_memory_jtype_, 0, sizeof(tbaa_memory_jtype_)); + + // Pre-generate the MDNode for static branch prediction + // 64 and 4 are the llvm.expect's default values + expect_cond_[kLikely] = createBranchWeights(64, 4); + expect_cond_[kUnlikely] = createBranchWeights(4, 64); + } + + ::llvm::MDNode* GetTBAASpecialType(TBAASpecialType special_ty); + ::llvm::MDNode* GetTBAAMemoryJType(TBAASpecialType special_ty, JType j_ty); + + ::llvm::MDNode* GetBranchWeights(ExpectCond expect) { + DCHECK_LT(expect, MAX_EXPECT) << "MAX_EXPECT is not for branch weight"; + return expect_cond_[expect]; + } + + private: + ::llvm::MDNode* const tbaa_root_; + ::llvm::MDNode* tbaa_special_type_[MAX_TBAA_SPECIAL_TYPE]; + // There are 3 categories of memory types will not alias: array element, instance field, and + // static field. + ::llvm::MDNode* tbaa_memory_jtype_[3][MAX_JTYPE]; + + ::llvm::MDNode* expect_cond_[MAX_EXPECT]; +}; + + +} // namespace llvm +} // namespace art + +#endif // ART_SRC_COMPILER_LLVM_MD_BUILDER_H_ diff --git a/compiler/llvm/runtime_support_builder.cc b/compiler/llvm/runtime_support_builder.cc new file mode 100644 index 0000000000..28405f67d4 --- /dev/null +++ b/compiler/llvm/runtime_support_builder.cc @@ -0,0 +1,281 @@ +/* + * 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 "runtime_support_builder.h" + +#include "gc/accounting/card_table.h" +#include "ir_builder.h" +#include "monitor.h" +#include "mirror/object.h" +#include "thread.h" + +#include <llvm/IR/DerivedTypes.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Type.h> + +using namespace llvm; + +namespace art { +namespace llvm { + +using namespace runtime_support; + + +RuntimeSupportBuilder::RuntimeSupportBuilder(::llvm::LLVMContext& context, + ::llvm::Module& module, + IRBuilder& irb) + : context_(context), module_(module), irb_(irb) +{ + memset(target_runtime_support_func_, 0, sizeof(target_runtime_support_func_)); +#define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \ + do { \ + ::llvm::Function* fn = module_.getFunction(#NAME); \ + DCHECK_NE(fn, (void*)NULL) << "Function not found: " << #NAME; \ + runtime_support_func_decls_[runtime_support::ID] = fn; \ + } while (0); + +#include "runtime_support_llvm_func_list.h" + RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL) +#undef RUNTIME_SUPPORT_FUNC_LIST +#undef GET_RUNTIME_SUPPORT_FUNC_DECL +} + + +/* Thread */ + +::llvm::Value* RuntimeSupportBuilder::EmitGetCurrentThread() { + Function* func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread); + CallInst* call_inst = irb_.CreateCall(func); + call_inst->setOnlyReadsMemory(); + irb_.SetTBAA(call_inst, kTBAAConstJObject); + return call_inst; +} + +::llvm::Value* RuntimeSupportBuilder::EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type, + TBAASpecialType s_ty) { + Value* thread = EmitGetCurrentThread(); + return irb_.LoadFromObjectOffset(thread, offset, type, s_ty); +} + +void RuntimeSupportBuilder::EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value, + TBAASpecialType s_ty) { + Value* thread = EmitGetCurrentThread(); + irb_.StoreToObjectOffset(thread, offset, value, s_ty); +} + +::llvm::Value* RuntimeSupportBuilder::EmitSetCurrentThread(::llvm::Value* thread) { + Function* func = GetRuntimeSupportFunction(runtime_support::SetCurrentThread); + return irb_.CreateCall(func, thread); +} + + +/* ShadowFrame */ + +::llvm::Value* RuntimeSupportBuilder::EmitPushShadowFrame(::llvm::Value* new_shadow_frame, + ::llvm::Value* method, + uint32_t num_vregs) { + Value* old_shadow_frame = EmitLoadFromThreadOffset(Thread::TopShadowFrameOffset().Int32Value(), + irb_.getArtFrameTy()->getPointerTo(), + kTBAARuntimeInfo); + EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(), + new_shadow_frame, + kTBAARuntimeInfo); + + // Store the method pointer + irb_.StoreToObjectOffset(new_shadow_frame, + ShadowFrame::MethodOffset(), + method, + kTBAAShadowFrame); + + // Store the number of vregs + irb_.StoreToObjectOffset(new_shadow_frame, + ShadowFrame::NumberOfVRegsOffset(), + irb_.getInt32(num_vregs), + kTBAAShadowFrame); + + // Store the link to previous shadow frame + irb_.StoreToObjectOffset(new_shadow_frame, + ShadowFrame::LinkOffset(), + old_shadow_frame, + kTBAAShadowFrame); + + return old_shadow_frame; +} + +::llvm::Value* +RuntimeSupportBuilder::EmitPushShadowFrameNoInline(::llvm::Value* new_shadow_frame, + ::llvm::Value* method, + uint32_t num_vregs) { + Function* func = GetRuntimeSupportFunction(runtime_support::PushShadowFrame); + ::llvm::CallInst* call_inst = + irb_.CreateCall4(func, + EmitGetCurrentThread(), + new_shadow_frame, + method, + irb_.getInt32(num_vregs)); + irb_.SetTBAA(call_inst, kTBAARuntimeInfo); + return call_inst; +} + +void RuntimeSupportBuilder::EmitPopShadowFrame(::llvm::Value* old_shadow_frame) { + // Store old shadow frame to TopShadowFrame + EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(), + old_shadow_frame, + kTBAARuntimeInfo); +} + + +/* Exception */ + +::llvm::Value* RuntimeSupportBuilder::EmitGetAndClearException() { + Function* slow_func = GetRuntimeSupportFunction(runtime_support::GetAndClearException); + return irb_.CreateCall(slow_func, EmitGetCurrentThread()); +} + +::llvm::Value* RuntimeSupportBuilder::EmitIsExceptionPending() { + Value* exception = EmitLoadFromThreadOffset(Thread::ExceptionOffset().Int32Value(), + irb_.getJObjectTy(), + kTBAARuntimeInfo); + // If exception not null + return irb_.CreateIsNotNull(exception); +} + + +/* Suspend */ + +void RuntimeSupportBuilder::EmitTestSuspend() { + Function* slow_func = GetRuntimeSupportFunction(runtime_support::TestSuspend); + CallInst* call_inst = irb_.CreateCall(slow_func, EmitGetCurrentThread()); + irb_.SetTBAA(call_inst, kTBAAJRuntime); +} + + +/* Monitor */ + +void RuntimeSupportBuilder::EmitLockObject(::llvm::Value* object) { + Value* monitor = + irb_.LoadFromObjectOffset(object, + mirror::Object::MonitorOffset().Int32Value(), + irb_.getJIntTy(), + kTBAARuntimeInfo); + + Value* real_monitor = + irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT)); + + // Is thin lock, unheld and not recursively acquired. + Value* unheld = irb_.CreateICmpEQ(real_monitor, irb_.getInt32(0)); + + Function* parent_func = irb_.GetInsertBlock()->getParent(); + BasicBlock* bb_fast = BasicBlock::Create(context_, "lock_fast", parent_func); + BasicBlock* bb_slow = BasicBlock::Create(context_, "lock_slow", parent_func); + BasicBlock* bb_cont = BasicBlock::Create(context_, "lock_cont", parent_func); + irb_.CreateCondBr(unheld, bb_fast, bb_slow, kLikely); + + irb_.SetInsertPoint(bb_fast); + + // Calculate new monitor: new = old | (lock_id << LW_LOCK_OWNER_SHIFT) + Value* lock_id = + EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(), + irb_.getInt32Ty(), kTBAARuntimeInfo); + + Value* owner = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT); + Value* new_monitor = irb_.CreateOr(monitor, owner); + + // Atomically update monitor. + Value* old_monitor = + irb_.CompareExchangeObjectOffset(object, + mirror::Object::MonitorOffset().Int32Value(), + monitor, new_monitor, kTBAARuntimeInfo); + + Value* retry_slow_path = irb_.CreateICmpEQ(old_monitor, monitor); + irb_.CreateCondBr(retry_slow_path, bb_cont, bb_slow, kLikely); + + irb_.SetInsertPoint(bb_slow); + Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject); + irb_.CreateCall2(slow_func, object, EmitGetCurrentThread()); + irb_.CreateBr(bb_cont); + + irb_.SetInsertPoint(bb_cont); +} + +void RuntimeSupportBuilder::EmitUnlockObject(::llvm::Value* object) { + Value* lock_id = + EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(), + irb_.getJIntTy(), + kTBAARuntimeInfo); + Value* monitor = + irb_.LoadFromObjectOffset(object, + mirror::Object::MonitorOffset().Int32Value(), + irb_.getJIntTy(), + kTBAARuntimeInfo); + + Value* my_monitor = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT); + Value* hash_state = irb_.CreateAnd(monitor, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT)); + Value* real_monitor = irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT)); + + // Is thin lock, held by us and not recursively acquired + Value* is_fast_path = irb_.CreateICmpEQ(real_monitor, my_monitor); + + Function* parent_func = irb_.GetInsertBlock()->getParent(); + BasicBlock* bb_fast = BasicBlock::Create(context_, "unlock_fast", parent_func); + BasicBlock* bb_slow = BasicBlock::Create(context_, "unlock_slow", parent_func); + BasicBlock* bb_cont = BasicBlock::Create(context_, "unlock_cont", parent_func); + irb_.CreateCondBr(is_fast_path, bb_fast, bb_slow, kLikely); + + irb_.SetInsertPoint(bb_fast); + // Set all bits to zero (except hash state) + irb_.StoreToObjectOffset(object, + mirror::Object::MonitorOffset().Int32Value(), + hash_state, + kTBAARuntimeInfo); + irb_.CreateBr(bb_cont); + + irb_.SetInsertPoint(bb_slow); + Function* slow_func = GetRuntimeSupportFunction(runtime_support::UnlockObject); + irb_.CreateCall2(slow_func, object, EmitGetCurrentThread()); + irb_.CreateBr(bb_cont); + + irb_.SetInsertPoint(bb_cont); +} + + +void RuntimeSupportBuilder::EmitMarkGCCard(::llvm::Value* value, ::llvm::Value* target_addr) { + Function* parent_func = irb_.GetInsertBlock()->getParent(); + BasicBlock* bb_mark_gc_card = BasicBlock::Create(context_, "mark_gc_card", parent_func); + BasicBlock* bb_cont = BasicBlock::Create(context_, "mark_gc_card_cont", parent_func); + + ::llvm::Value* not_null = irb_.CreateIsNotNull(value); + irb_.CreateCondBr(not_null, bb_mark_gc_card, bb_cont); + + irb_.SetInsertPoint(bb_mark_gc_card); + Value* card_table = EmitLoadFromThreadOffset(Thread::CardTableOffset().Int32Value(), + irb_.getInt8Ty()->getPointerTo(), + kTBAAConstJObject); + Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy()); + Value* card_no = irb_.CreateLShr(target_addr_int, + irb_.getPtrEquivInt(gc::accounting::CardTable::kCardShift)); + Value* card_table_entry = irb_.CreateGEP(card_table, card_no); + irb_.CreateStore(irb_.getInt8(gc::accounting::CardTable::kCardDirty), card_table_entry, + kTBAARuntimeInfo); + irb_.CreateBr(bb_cont); + + irb_.SetInsertPoint(bb_cont); +} + + +} // namespace llvm +} // namespace art diff --git a/compiler/llvm/runtime_support_builder.h b/compiler/llvm/runtime_support_builder.h new file mode 100644 index 0000000000..267b406232 --- /dev/null +++ b/compiler/llvm/runtime_support_builder.h @@ -0,0 +1,98 @@ +/* + * 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_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_ +#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_ + +#include "backend_types.h" +#include "base/logging.h" +#include "runtime_support_llvm_func.h" + +#include <stdint.h> + +namespace llvm { + class LLVMContext; + class Module; + class Function; + class Type; + class Value; +} + +namespace art { +namespace llvm { + +class IRBuilder; + + +class RuntimeSupportBuilder { + public: + RuntimeSupportBuilder(::llvm::LLVMContext& context, ::llvm::Module& module, IRBuilder& irb); + + /* Thread */ + virtual ::llvm::Value* EmitGetCurrentThread(); + virtual ::llvm::Value* EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type, + TBAASpecialType s_ty); + virtual void EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value, + TBAASpecialType s_ty); + virtual ::llvm::Value* EmitSetCurrentThread(::llvm::Value* thread); + + /* ShadowFrame */ + virtual ::llvm::Value* EmitPushShadowFrame(::llvm::Value* new_shadow_frame, + ::llvm::Value* method, uint32_t num_vregs); + virtual ::llvm::Value* EmitPushShadowFrameNoInline(::llvm::Value* new_shadow_frame, + ::llvm::Value* method, uint32_t num_vregs); + virtual void EmitPopShadowFrame(::llvm::Value* old_shadow_frame); + + /* Exception */ + virtual ::llvm::Value* EmitGetAndClearException(); + virtual ::llvm::Value* EmitIsExceptionPending(); + + /* Suspend */ + virtual void EmitTestSuspend(); + + /* Monitor */ + virtual void EmitLockObject(::llvm::Value* object); + virtual void EmitUnlockObject(::llvm::Value* object); + + /* MarkGCCard */ + virtual void EmitMarkGCCard(::llvm::Value* value, ::llvm::Value* target_addr); + + ::llvm::Function* GetRuntimeSupportFunction(runtime_support::RuntimeId id) { + if (id >= 0 && id < runtime_support::MAX_ID) { + return runtime_support_func_decls_[id]; + } else { + LOG(ERROR) << "Unknown runtime function id: " << id; + return NULL; + } + } + + virtual ~RuntimeSupportBuilder() {} + + protected: + ::llvm::LLVMContext& context_; + ::llvm::Module& module_; + IRBuilder& irb_; + + private: + ::llvm::Function* runtime_support_func_decls_[runtime_support::MAX_ID]; + bool target_runtime_support_func_[runtime_support::MAX_ID]; +}; + + +} // namespace llvm +} // namespace art + +#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_ diff --git a/compiler/llvm/runtime_support_builder_arm.cc b/compiler/llvm/runtime_support_builder_arm.cc new file mode 100644 index 0000000000..57a997135e --- /dev/null +++ b/compiler/llvm/runtime_support_builder_arm.cc @@ -0,0 +1,134 @@ +/* + * 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_arm.h" + +#include "ir_builder.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 <vector> + +using namespace llvm; + +namespace { + +char LDRSTRSuffixByType(art::llvm::IRBuilder& irb, ::llvm::Type* type) { + int width = type->isPointerTy() ? + irb.getSizeOfPtrEquivInt()*8 : + ::llvm::cast<IntegerType>(type)->getBitWidth(); + switch (width) { + case 8: return 'b'; + case 16: return 'h'; + case 32: return ' '; + default: + LOG(FATAL) << "Unsupported width: " << width; + return ' '; + } +} + +} // namespace + +namespace art { +namespace llvm { + +/* Thread */ + +::llvm::Value* RuntimeSupportBuilderARM::EmitGetCurrentThread() { + Function* ori_func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread); + InlineAsm* func = InlineAsm::get(ori_func->getFunctionType(), "mov $0, r9", "=r", false); + CallInst* thread = irb_.CreateCall(func); + thread->setDoesNotAccessMemory(); + irb_.SetTBAA(thread, kTBAAConstJObject); + return thread; +} + +::llvm::Value* RuntimeSupportBuilderARM::EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type, + TBAASpecialType s_ty) { + FunctionType* func_ty = FunctionType::get(/*Result=*/type, + /*isVarArg=*/false); + std::string inline_asm(StringPrintf("ldr%c $0, [r9, #%d]", + LDRSTRSuffixByType(irb_, type), + static_cast<int>(offset))); + InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "=r", true); + CallInst* result = irb_.CreateCall(func); + result->setOnlyReadsMemory(); + irb_.SetTBAA(result, s_ty); + return result; +} + +void RuntimeSupportBuilderARM::EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value, + TBAASpecialType s_ty) { + FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_), + /*Params=*/value->getType(), + /*isVarArg=*/false); + std::string inline_asm(StringPrintf("str%c $0, [r9, #%d]", + LDRSTRSuffixByType(irb_, value->getType()), + static_cast<int>(offset))); + InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "r", true); + CallInst* call_inst = irb_.CreateCall(func, value); + irb_.SetTBAA(call_inst, s_ty); +} + +::llvm::Value* +RuntimeSupportBuilderARM::EmitSetCurrentThread(::llvm::Value* thread) { + // Separate to two InlineAsm: The first one produces the return value, while the second, + // sets the current thread. + // LLVM can delete the first one if the caller in LLVM IR doesn't use the return value. + // + // Here we don't call EmitGetCurrentThread, because we mark it as DoesNotAccessMemory and + // ConstJObject. We denote side effect to "true" below instead, so LLVM won't + // reorder these instructions incorrectly. + Function* ori_func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread); + InlineAsm* func = InlineAsm::get(ori_func->getFunctionType(), "mov $0, r9", "=r", true); + CallInst* old_thread_register = irb_.CreateCall(func); + old_thread_register->setOnlyReadsMemory(); + + FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_), + /*Params=*/irb_.getJObjectTy(), + /*isVarArg=*/false); + func = InlineAsm::get(func_ty, "mov r9, $0", "r", true); + irb_.CreateCall(func, thread); + return old_thread_register; +} + + +/* Monitor */ + +void RuntimeSupportBuilderARM::EmitLockObject(::llvm::Value* object) { + RuntimeSupportBuilder::EmitLockObject(object); + FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_), + /*isVarArg=*/false); + InlineAsm* func = InlineAsm::get(func_ty, "dmb sy", "", true); + irb_.CreateCall(func); +} + +void RuntimeSupportBuilderARM::EmitUnlockObject(::llvm::Value* object) { + RuntimeSupportBuilder::EmitUnlockObject(object); + FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_), + /*isVarArg=*/false); + InlineAsm* func = InlineAsm::get(func_ty, "dmb sy", "", true); + irb_.CreateCall(func); +} + +} // namespace llvm +} // namespace art diff --git a/compiler/llvm/runtime_support_builder_arm.h b/compiler/llvm/runtime_support_builder_arm.h new file mode 100644 index 0000000000..3c5972fc33 --- /dev/null +++ b/compiler/llvm/runtime_support_builder_arm.h @@ -0,0 +1,46 @@ +/* + * 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_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_ +#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_ + +#include "runtime_support_builder.h" + +namespace art { +namespace llvm { + +class RuntimeSupportBuilderARM : public RuntimeSupportBuilder { + public: + RuntimeSupportBuilderARM(::llvm::LLVMContext& context, ::llvm::Module& module, IRBuilder& irb) + : RuntimeSupportBuilder(context, module, irb) {} + + /* Thread */ + virtual ::llvm::Value* EmitGetCurrentThread(); + virtual ::llvm::Value* EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type, + TBAASpecialType s_ty); + virtual void EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value, + TBAASpecialType s_ty); + virtual ::llvm::Value* EmitSetCurrentThread(::llvm::Value* thread); + + /* Monitor */ + virtual void EmitLockObject(::llvm::Value* object); + virtual void EmitUnlockObject(::llvm::Value* object); +}; + +} // namespace llvm +} // namespace art + +#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_ 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 diff --git a/compiler/llvm/runtime_support_builder_thumb2.h b/compiler/llvm/runtime_support_builder_thumb2.h new file mode 100644 index 0000000000..4762a269f9 --- /dev/null +++ b/compiler/llvm/runtime_support_builder_thumb2.h @@ -0,0 +1,37 @@ +/* + * 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_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_THUMB2_H_ +#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_THUMB2_H_ + +#include "runtime_support_builder_arm.h" + +namespace art { +namespace llvm { + +class RuntimeSupportBuilderThumb2 : public RuntimeSupportBuilderARM { + public: + RuntimeSupportBuilderThumb2(::llvm::LLVMContext& context, ::llvm::Module& module, IRBuilder& irb) + : RuntimeSupportBuilderARM(context, module, irb) {} + + /* Monitor */ + virtual void EmitLockObject(::llvm::Value* object); +}; + +} // namespace llvm +} // namespace art + +#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_THUMB2_H_ diff --git a/compiler/llvm/runtime_support_builder_x86.cc b/compiler/llvm/runtime_support_builder_x86.cc new file mode 100644 index 0000000000..eed0b63d76 --- /dev/null +++ b/compiler/llvm/runtime_support_builder_x86.cc @@ -0,0 +1,78 @@ +/* + * 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_x86.h" + +#include "base/stringprintf.h" +#include "ir_builder.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 <vector> + +using namespace llvm; + +namespace art { +namespace llvm { + + +::llvm::Value* RuntimeSupportBuilderX86::EmitGetCurrentThread() { + Function* ori_func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread); + std::string inline_asm(StringPrintf("mov %%fs:%d, $0", Thread::SelfOffset().Int32Value())); + InlineAsm* func = InlineAsm::get(ori_func->getFunctionType(), inline_asm, "=r", false); + CallInst* thread = irb_.CreateCall(func); + thread->setDoesNotAccessMemory(); + irb_.SetTBAA(thread, kTBAAConstJObject); + return thread; +} + +::llvm::Value* RuntimeSupportBuilderX86::EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type, + TBAASpecialType s_ty) { + FunctionType* func_ty = FunctionType::get(/*Result=*/type, + /*isVarArg=*/false); + std::string inline_asm(StringPrintf("mov %%fs:%d, $0", static_cast<int>(offset))); + InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "=r", true); + CallInst* result = irb_.CreateCall(func); + result->setOnlyReadsMemory(); + irb_.SetTBAA(result, s_ty); + return result; +} + +void RuntimeSupportBuilderX86::EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value, + TBAASpecialType s_ty) { + FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_), + /*Params=*/value->getType(), + /*isVarArg=*/false); + std::string inline_asm(StringPrintf("mov $0, %%fs:%d", static_cast<int>(offset))); + InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "r", true); + CallInst* call_inst = irb_.CreateCall(func, value); + irb_.SetTBAA(call_inst, s_ty); +} + +::llvm::Value* RuntimeSupportBuilderX86::EmitSetCurrentThread(::llvm::Value*) { + /* Nothing to be done. */ + return ::llvm::UndefValue::get(irb_.getJObjectTy()); +} + + +} // namespace llvm +} // namespace art diff --git a/compiler/llvm/runtime_support_builder_x86.h b/compiler/llvm/runtime_support_builder_x86.h new file mode 100644 index 0000000000..e5fdbc2e26 --- /dev/null +++ b/compiler/llvm/runtime_support_builder_x86.h @@ -0,0 +1,42 @@ +/* + * 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_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_ +#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_ + +#include "runtime_support_builder.h" + +namespace art { +namespace llvm { + +class RuntimeSupportBuilderX86 : public RuntimeSupportBuilder { + public: + RuntimeSupportBuilderX86(::llvm::LLVMContext& context, ::llvm::Module& module, IRBuilder& irb) + : RuntimeSupportBuilder(context, module, irb) {} + + /* Thread */ + virtual ::llvm::Value* EmitGetCurrentThread(); + virtual ::llvm::Value* EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type, + TBAASpecialType s_ty); + virtual void EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value, + TBAASpecialType s_ty); + virtual ::llvm::Value* EmitSetCurrentThread(::llvm::Value* thread); +}; + +} // namespace llvm +} // namespace art + +#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_ diff --git a/compiler/llvm/runtime_support_llvm_func.h b/compiler/llvm/runtime_support_llvm_func.h new file mode 100644 index 0000000000..ac6f3b869f --- /dev/null +++ b/compiler/llvm/runtime_support_llvm_func.h @@ -0,0 +1,38 @@ +/* + * 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_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_FUNC_H_ +#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_FUNC_H_ + +namespace art { +namespace llvm { +namespace runtime_support { + + enum RuntimeId { +#define DEFINE_RUNTIME_SUPPORT_FUNC_ID(ID, NAME) ID, +#include "runtime_support_llvm_func_list.h" + RUNTIME_SUPPORT_FUNC_LIST(DEFINE_RUNTIME_SUPPORT_FUNC_ID) +#undef RUNTIME_SUPPORT_FUNC_LIST +#undef DEFINE_RUNTIME_SUPPORT_FUNC_ID + + MAX_ID + }; + +} // namespace runtime_support +} // namespace llvm +} // namespace art + +#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_FUNC_H_ diff --git a/compiler/llvm/tools/gen_art_module_cc.sh b/compiler/llvm/tools/gen_art_module_cc.sh new file mode 100755 index 0000000000..c5df333e34 --- /dev/null +++ b/compiler/llvm/tools/gen_art_module_cc.sh @@ -0,0 +1,50 @@ +#!/bin/bash -e + +# 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. + +SCRIPTDIR=`dirname "$0"` +cd "${SCRIPTDIR}/.." + +mkdir -p generated + +OUTPUT_FILE=generated/art_module.cc + +echo "// Generated with ${0}" > ${OUTPUT_FILE} + +echo ' + +#pragma GCC diagnostic ignored "-Wframe-larger-than=" +// TODO: Remove this pragma after llc can generate makeLLVMModuleContents() +// with smaller frame size. + +#include <llvm/IR/DerivedTypes.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Type.h> + +#include <vector> + +using namespace llvm; + +namespace art { +namespace llvm { + +' >> ${OUTPUT_FILE} + +llc -march=cpp -cppgen=contents art_module.ll -o - >> ${OUTPUT_FILE} + +echo ' +} // namespace llvm +} // namespace art' >> ${OUTPUT_FILE} diff --git a/compiler/llvm/utils_llvm.h b/compiler/llvm/utils_llvm.h new file mode 100644 index 0000000000..2e273f4fe9 --- /dev/null +++ b/compiler/llvm/utils_llvm.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef ART_SRC_UTILS_LLVM_H_ +#define ART_SRC_UTILS_LLVM_H_ + +#include <llvm/Analysis/Verifier.h> + +namespace art { + +#ifndef NDEBUG +#define VERIFY_LLVM_FUNCTION(func) ::llvm::verifyFunction(func, ::llvm::AbortProcessAction) +#else +#define VERIFY_LLVM_FUNCTION(func) +#endif + +} // namespace art + +#endif // ART_SRC_UTILS_LLVM_H_ |