Compile llvm.Module into ELF object file.
Change-Id: I8faf7427944324c9bac12573d217cde2a2e658f1
diff --git a/build/Android.common.mk b/build/Android.common.mk
index d564735..3f6b84b 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -204,6 +204,7 @@
ifeq ($(ART_USE_LLVM_COMPILER),true)
LIBART_COMMON_SRC_FILES += \
+ src/compiler_llvm/compilation_unit.cc \
src/compiler_llvm/compiler_llvm.cc \
src/compiler_llvm/dalvik_reg.cc \
src/compiler_llvm/frontend.cc \
diff --git a/build/Android.libart.mk b/build/Android.libart.mk
index d7ebefe..b049ad9 100644
--- a/build/Android.libart.mk
+++ b/build/Android.libart.mk
@@ -71,7 +71,58 @@
endif
LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
ifeq ($(ART_USE_LLVM_COMPILER),true)
- LOCAL_STATIC_LIBRARIES += libLLVMBitWriter libLLVMCore libLLVMSupport
+ libart_arm_STATIC_LIBRARIES := \
+ libLLVMARMInfo \
+ libLLVMARMDisassembler \
+ libLLVMARMAsmParser \
+ libLLVMARMAsmPrinter \
+ libLLVMARMCodeGen \
+ libLLVMARMDesc
+
+ libart_mips_STATIC_LIBRARIES := \
+ libLLVMMipsInfo \
+ libLLVMMipsCodeGen \
+ libLLVMMipsDesc \
+ libLLVMMipsAsmPrinter \
+
+ libart_x86_STATIC_LIBRARIES := \
+ libLLVMX86Info \
+ libLLVMX86AsmParser \
+ libLLVMX86CodeGen \
+ libLLVMX86Disassembler \
+ libLLVMX86Desc \
+ libLLVMX86AsmPrinter \
+ libLLVMX86Utils
+
+ ifeq ($$(art_target_or_host),target)
+ LOCAL_STATIC_LIBRARIES += \
+ $$(libart_arm_STATIC_LIBRARIES)
+ else
+ LOCAL_STATIC_LIBRARIES += \
+ $$(libart_arm_STATIC_LIBRARIES) \
+ $$(libart_mips_STATIC_LIBRARIES) \
+ $$(libart_x86_STATIC_LIBRARIES)
+ endif
+
+ LOCAL_STATIC_LIBRARIES += \
+ libLLVMLinker \
+ libLLVMipo \
+ libLLVMBitWriter \
+ libLLVMBitReader \
+ libLLVMAsmPrinter \
+ libLLVMSelectionDAG \
+ libLLVMCodeGen \
+ libLLVMScalarOpts \
+ libLLVMInstCombine \
+ libLLVMInstrumentation \
+ libLLVMTransformUtils \
+ libLLVMipa \
+ libLLVMAnalysis \
+ libLLVMTarget \
+ libLLVMMC \
+ libLLVMMCParser \
+ libLLVMCore \
+ libLLVMSupport
endif
LOCAL_SHARED_LIBRARIES := liblog libnativehelper
ifeq ($$(art_target_or_host),target)
diff --git a/src/compiler.cc b/src/compiler.cc
index 4664987..40874f5 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -347,7 +347,7 @@
const std::vector<const DexFile*>& dex_files) {
SetGcMaps(class_loader, dex_files);
#if defined(ART_USE_LLVM_COMPILER)
- compiler_llvm_->MaterializeLLVMModule();
+ compiler_llvm_->MaterializeEveryCompilationUnit();
#endif
}
@@ -1149,4 +1149,14 @@
compiled_method->SetGcMap(*gc_map);
}
+#if defined(ART_USE_LLVM_COMPILER)
+void Compiler::SetElfFileName(std::string const& filename) {
+ compiler_llvm_->SetElfFileName(filename);
+}
+
+void Compiler::SetBitcodeFileName(std::string const& filename) {
+ compiler_llvm_->SetBitcodeFileName(filename);
+}
+#endif
+
} // namespace art
diff --git a/src/compiler.h b/src/compiler.h
index 27de42f..2ff3b90 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -124,6 +124,9 @@
int& vtable_idx);
#if defined(ART_USE_LLVM_COMPILER)
+ void SetElfFileName(std::string const& filename);
+ void SetBitcodeFileName(std::string const& filename);
+
compiler_llvm::CompilerLLVM* GetCompilerLLVM() const {
return compiler_llvm_.get();
}
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
new file mode 100644
index 0000000..45c4bb7
--- /dev/null
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -0,0 +1,218 @@
+/*
+ * 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 "compilation_unit.h"
+
+#include "constants.h"
+#include "ir_builder.h"
+#include "logging.h"
+
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/ADT/StringSet.h>
+#include <llvm/ADT/Triple.h>
+#include <llvm/Analysis/CallGraph.h>
+#include <llvm/Analysis/DebugInfo.h>
+#include <llvm/Analysis/LoopPass.h>
+#include <llvm/Analysis/RegionPass.h>
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/Assembly/PrintModulePass.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/CallGraphSCCPass.h>
+#include <llvm/DerivedTypes.h>
+#include <llvm/LLVMContext.h>
+#include <llvm/LinkAllPasses.h>
+#include <llvm/LinkAllVMCore.h>
+#include <llvm/Module.h>
+#include <llvm/PassManager.h>
+#include <llvm/Support/Debug.h>
+#include <llvm/Support/FormattedStream.h>
+#include <llvm/Support/ManagedStatic.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/Target/TargetData.h>
+#include <llvm/Target/TargetLibraryInfo.h>
+#include <llvm/Target/TargetMachine.h>
+#include <llvm/Transforms/IPO/PassManagerBuilder.h>
+
+#include <string>
+
+namespace art {
+namespace compiler_llvm {
+
+llvm::Module* makeLLVMModuleContents(llvm::Module* module);
+
+
+CompilationUnit::CompilationUnit(InstructionSet insn_set)
+: insn_set_(insn_set), context_(new llvm::LLVMContext()), mem_usage_(0) {
+
+ // Create the module and include the runtime function declaration
+ module_ = new llvm::Module("art", *context_);
+ makeLLVMModuleContents(module_);
+
+ // Create IRBuilder
+ irb_.reset(new IRBuilder(*context_, *module_));
+}
+
+
+CompilationUnit::~CompilationUnit() {
+}
+
+
+bool CompilationUnit::WriteBitcodeToFile() {
+ 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();
+
+ return true;
+}
+
+
+bool CompilationUnit::Materialize() {
+ // Initialize LLVM optimization passes
+ llvm::PassRegistry &Registry = *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);
+
+ // Lookup the LLVM target
+ char const* target_triple = NULL;
+ char const* target_attr = NULL;
+
+ if (insn_set_ == kThumb2) {
+ target_triple = "thumb-none-linux-gnueabi";
+ target_attr = "+thumb2,+neon,+neonfp,+vfp3";
+ } else if (insn_set_ == kArm) {
+ target_triple = "armv7-none-linux-gnueabi";
+ target_attr = "+v7,+neon,+neonfp,+vfp3";
+ } else if (insn_set_ == kX86) {
+ target_triple = "i386-pc-linux-gnu";
+ target_attr = "";
+ // } else if (insn_set_ == kMips) {
+ // target_triple = "mipsel-unknown-linux";
+ // target_attr = "";
+ } else {
+ LOG(FATAL) << "Unknown instruction set: " << insn_set_;
+ }
+
+ std::string errmsg;
+ llvm::Target const* 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.UseSoftFloat = false;
+
+ // Create the llvm::TargetMachine
+ llvm::TargetMachine* target_machine =
+ target->createTargetMachine(target_triple, "", target_attr, target_options,
+ llvm::Reloc::Static, llvm::CodeModel::Small,
+ llvm::CodeGenOpt::Aggressive);
+
+ CHECK(target_machine != NULL) << "Failed to create target machine";
+
+
+ // Add target data
+ llvm::TargetData const* target_data = target_machine->getTargetData();
+
+ // PassManager for code generation passes
+ llvm::PassManager pm;
+ pm.add(new llvm::TargetData(*target_data));
+
+ // FunctionPassManager for optimization pass
+ llvm::FunctionPassManager fpm(module_);
+ fpm.add(new llvm::TargetData(*target_data));
+
+ // Add optimization pass
+ llvm::PassManagerBuilder pm_builder;
+ pm_builder.Inliner = NULL; // TODO: add some inline in the future
+ pm_builder.OptLevel = 3;
+ pm_builder.DisableSimplifyLibCalls = 1;
+ pm_builder.populateModulePassManager(pm);
+ pm_builder.populateFunctionPassManager(fpm);
+
+ // Add passes to emit file
+ llvm::OwningPtr<llvm::tool_output_file> out_file(
+ new llvm::tool_output_file(elf_filename_.c_str(), errmsg,
+ llvm::raw_fd_ostream::F_Binary));
+
+ llvm::formatted_raw_ostream formatted_os(out_file->os(), 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();
+ LOG(INFO) << "Intraprocedural optimization finished!";
+
+ // Run the code generation passes
+ pm.run(*module_);
+ LOG(INFO) << "Code generation finished!";
+
+ out_file->keep();
+ LOG(DEBUG) << "ELF: " << elf_filename_ << " (done)";
+
+ return true;
+}
+
+
+void CompilationUnit::Finalize() {
+ context_.reset(NULL);
+ irb_.reset(NULL);
+ module_ = NULL;
+}
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h
new file mode 100644
index 0000000..a10d977
--- /dev/null
+++ b/src/compiler_llvm/compilation_unit.h
@@ -0,0 +1,110 @@
+/*
+ * 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_COMPILATION_UNIT_H_
+#define ART_SRC_COMPILER_LLVM_COMPILATION_UNIT_H_
+
+#include "constants.h"
+#include "logging.h"
+
+#include <UniquePtr.h>
+#include <string>
+
+namespace llvm {
+ class LLVMContext;
+ class Module;
+}
+
+namespace art {
+namespace compiler_llvm {
+
+class IRBuilder;
+
+class CompilationUnit {
+ public:
+ CompilationUnit(InstructionSet insn_set);
+
+ ~CompilationUnit();
+
+ InstructionSet GetInstructionSet() const {
+ return insn_set_;
+ }
+
+ llvm::LLVMContext* GetLLVMContext() const {
+ return context_.get();
+ }
+
+ llvm::Module* GetModule() const {
+ return module_;
+ }
+
+ IRBuilder* GetIRBuilder() const {
+ return irb_.get();
+ }
+
+ std::string const& GetElfFileName() const {
+ CHECK(IsFinalized());
+ return elf_filename_;
+ }
+
+ std::string const& GetBitcodeFileName() const {
+ CHECK(IsFinalized());
+ return bitcode_filename_;
+ }
+
+ void SetElfFileName(std::string const& filename) {
+ elf_filename_ = filename;
+ }
+
+ void SetBitcodeFileName(std::string const& filename) {
+ bitcode_filename_ = filename;
+ }
+
+ bool WriteBitcodeToFile();
+
+ bool Materialize();
+
+ bool IsFinalized() const {
+ return (context_.get() == NULL);
+ }
+
+ void Finalize();
+
+ bool IsMaterializeThresholdReached() const {
+ return (mem_usage_ > 300000000u); // (threshold: 300 MB)
+ }
+
+ void AddMemUsageApproximation(size_t usage) {
+ mem_usage_ += usage;
+ }
+
+ private:
+ InstructionSet insn_set_;
+
+ UniquePtr<llvm::LLVMContext> context_;
+ UniquePtr<IRBuilder> irb_;
+ llvm::Module* module_;
+
+ std::string elf_filename_;
+ std::string bitcode_filename_;
+
+ size_t mem_usage_;
+};
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_COMPILATION_UNIT_H_
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 1489ec4..56f0b07 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -16,6 +16,7 @@
#include "compiler_llvm.h"
+#include "compilation_unit.h"
#include "compiler.h"
#include "ir_builder.h"
#include "jni_compiler.h"
@@ -23,12 +24,28 @@
#include "oat_compilation_unit.h"
#include "upcall_compiler.h"
-#include <llvm/ADT/OwningPtr.h>
-#include <llvm/Bitcode/ReaderWriter.h>
-#include <llvm/DerivedTypes.h>
-#include <llvm/LLVMContext.h>
-#include <llvm/Module.h>
-#include <llvm/Support/ToolOutputFile.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Support/Threading.h>
+
+
+namespace {
+
+pthread_once_t llvm_initialized = PTHREAD_ONCE_INIT;
+
+void InitializeLLVM() {
+ // Initialize LLVM target, MC subsystem, asm printer, and asm parser
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllAsmParsers();
+ // TODO: Maybe we don't have to initialize "all" targets.
+
+ // Initialize LLVM internal data structure for multithreading
+ llvm::llvm_start_multithreaded();
+}
+
+} // anonymous namespace
+
namespace art {
namespace compiler_llvm {
@@ -39,67 +56,93 @@
CompilerLLVM::CompilerLLVM(Compiler* compiler, InstructionSet insn_set)
: compiler_(compiler), compiler_lock_("llvm_compiler_lock"),
- insn_set_(insn_set), context_(new llvm::LLVMContext()) {
+ insn_set_(insn_set), cunit_counter_(0) {
- // Create the module and include the runtime function declaration
- module_ = new llvm::Module("art", *context_);
- makeLLVMModuleContents(module_);
-
- // Create IRBuilder
- irb_.reset(new IRBuilder(*context_, *module_));
+ // Initialize LLVM libraries
+ pthread_once(&llvm_initialized, InitializeLLVM);
}
CompilerLLVM::~CompilerLLVM() {
+ DCHECK(cunit_.get() == NULL);
}
-void CompilerLLVM::MaterializeLLVMModule() {
-#if !defined(NDEBUG)
- // TODO: Add options to JNI_CreateJavaVM() and dex2oat, so that we don't
- // have to hard-code the path.
- WriteBitcodeToFile("/tmp/art_llvm_module.bc");
-#endif
+void CompilerLLVM::EnsureCompilationUnit() {
+ DCHECK_NE(llvm_initialized, PTHREAD_ONCE_INIT);
+ if (cunit_.get() == NULL) {
+ cunit_.reset(new CompilationUnit(insn_set_));
+ }
}
-void CompilerLLVM::WriteBitcodeToFile(std::string const &filepath) {
- std::string error_msg;
+void CompilerLLVM::MaterializeEveryCompilationUnit() {
+ if (cunit_.get() != NULL) {
+ MaterializeCompilationUnit();
+ }
+}
- // Write the translated bitcode
- llvm::OwningPtr<llvm::tool_output_file>
- out(new llvm::tool_output_file(filepath.c_str(), error_msg,
- llvm::raw_fd_ostream::F_Binary));
- if (!error_msg.empty()) {
- LOG(FATAL) << "Unable to open file: " << error_msg;
- return;
+void CompilerLLVM::MaterializeCompilationUnitSafePoint() {
+ if (cunit_->IsMaterializeThresholdReached()) {
+ MaterializeCompilationUnit();
+ }
+}
+
+
+void CompilerLLVM::MaterializeCompilationUnit() {
+ MutexLock GUARD(compiler_lock_);
+
+ cunit_->SetElfFileName(StringPrintf("%s-%u", elf_filename_.c_str(),
+ cunit_counter_));
+
+ // Write the translated bitcode for debugging
+ if (!bitcode_filename_.empty()) {
+ cunit_->SetBitcodeFileName(StringPrintf("%s-%u", bitcode_filename_.c_str(),
+ cunit_counter_));
+ cunit_->WriteBitcodeToFile();
}
- llvm::WriteBitcodeToFile(module_, out->os());
- out->keep();
+ // Materialize the llvm::Module into ELF object file
+ cunit_->Materialize();
- LOG(DEBUG) << "Bitcode Written At: " << filepath;
+ // Increase compilation unit counter
+ ++cunit_counter_;
+
+ // Delete the compilation unit
+ cunit_.reset(NULL);
}
CompiledMethod* CompilerLLVM::CompileDexMethod(OatCompilationUnit* oat_compilation_unit) {
MutexLock GUARD(compiler_lock_);
- UniquePtr<MethodCompiler> method_compiler(
- new MethodCompiler(insn_set_, compiler_, oat_compilation_unit));
+ EnsureCompilationUnit();
- return method_compiler->Compile();
+ UniquePtr<MethodCompiler> method_compiler(
+ new MethodCompiler(cunit_.get(), compiler_, oat_compilation_unit));
+
+ CompiledMethod* result = method_compiler->Compile();
+
+ MaterializeCompilationUnitSafePoint();
+
+ return result;
}
CompiledMethod* CompilerLLVM::CompileNativeMethod(OatCompilationUnit* oat_compilation_unit) {
MutexLock GUARD(compiler_lock_);
- UniquePtr<JniCompiler> jni_compiler(
- new JniCompiler(insn_set_, *compiler_, oat_compilation_unit));
+ EnsureCompilationUnit();
- return jni_compiler->Compile();
+ UniquePtr<JniCompiler> jni_compiler(
+ new JniCompiler(cunit_.get(), *compiler_, oat_compilation_unit));
+
+ CompiledMethod* result = jni_compiler->Compile();
+
+ MaterializeCompilationUnitSafePoint();
+
+ return result;
}
@@ -108,10 +151,16 @@
MutexLock GUARD(compiler_lock_);
- UniquePtr<UpcallCompiler> upcall_compiler(
- new UpcallCompiler(insn_set_, *compiler_));
+ EnsureCompilationUnit();
- return upcall_compiler->CreateStub(is_static, shorty);
+ UniquePtr<UpcallCompiler> upcall_compiler(
+ new UpcallCompiler(cunit_.get(), *compiler_));
+
+ CompiledInvokeStub* result = upcall_compiler->CreateStub(is_static, shorty);
+
+ MaterializeCompilationUnitSafePoint();
+
+ return result;
}
diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h
index 29d32a5..208edfc 100644
--- a/src/compiler_llvm/compiler_llvm.h
+++ b/src/compiler_llvm/compiler_llvm.h
@@ -47,6 +47,7 @@
namespace art {
namespace compiler_llvm {
+class CompilationUnit;
class IRBuilder;
class CompilerLLVM {
@@ -55,9 +56,7 @@
~CompilerLLVM();
- void MaterializeLLVMModule();
-
- void WriteBitcodeToFile(std::string const &filename);
+ void MaterializeEveryCompilationUnit();
Compiler* GetCompiler() const {
return compiler_;
@@ -67,16 +66,12 @@
return insn_set_;
}
- llvm::Module* GetModule() const {
- return module_;
+ void SetElfFileName(std::string const& filename) {
+ elf_filename_ = filename;
}
- llvm::LLVMContext* GetLLVMContext() const {
- return context_.get();
- }
-
- IRBuilder* GetIRBuilder() const {
- return irb_.get();
+ void SetBitcodeFileName(std::string const& filename) {
+ bitcode_filename_ = filename;
}
CompiledMethod* CompileDexMethod(OatCompilationUnit* oat_compilation_unit);
@@ -86,17 +81,25 @@
CompiledInvokeStub* CreateInvokeStub(bool is_static, char const *shorty);
private:
+ void EnsureCompilationUnit();
+
+ void MaterializeCompilationUnit();
+
+ void MaterializeCompilationUnitSafePoint();
+
Compiler* compiler_;
Mutex compiler_lock_;
InstructionSet insn_set_;
- UniquePtr<llvm::LLVMContext> context_;
+ UniquePtr<CompilationUnit> cunit_;
- UniquePtr<IRBuilder> irb_;
+ unsigned cunit_counter_;
- llvm::Module* module_;
+ std::string elf_filename_;
+
+ std::string bitcode_filename_;
DISALLOW_COPY_AND_ASSIGN(CompilerLLVM);
};
diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc
index f97e4fe..0e02846 100644
--- a/src/compiler_llvm/jni_compiler.cc
+++ b/src/compiler_llvm/jni_compiler.cc
@@ -17,6 +17,7 @@
#include "jni_compiler.h"
#include "class_linker.h"
+#include "compilation_unit.h"
#include "compiled_method.h"
#include "compiler.h"
#include "compiler_llvm.h"
@@ -35,14 +36,11 @@
namespace compiler_llvm {
-JniCompiler::JniCompiler(InstructionSet insn_set,
+JniCompiler::JniCompiler(CompilationUnit* cunit,
Compiler const& compiler,
OatCompilationUnit* oat_compilation_unit)
-: insn_set_(insn_set), compiler_(&compiler),
- compiler_llvm_(compiler_->GetCompilerLLVM()),
- module_(compiler_llvm_->GetModule()),
- context_(compiler_llvm_->GetLLVMContext()),
- irb_(*compiler_llvm_->GetIRBuilder()),
+: cunit_(cunit), compiler_(&compiler), module_(cunit_->GetModule()),
+ context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()),
oat_compilation_unit_(oat_compilation_unit),
access_flags_(oat_compilation_unit->access_flags_),
method_idx_(oat_compilation_unit->method_idx_),
@@ -63,7 +61,7 @@
CompiledMethod* JniCompiler::Compile() {
CreateFunction();
- return new CompiledMethod(insn_set_, func_);
+ return new CompiledMethod(cunit_->GetInstructionSet(), func_);
}
diff --git a/src/compiler_llvm/jni_compiler.h b/src/compiler_llvm/jni_compiler.h
index 4d7763e..a6cdd9c 100644
--- a/src/compiler_llvm/jni_compiler.h
+++ b/src/compiler_llvm/jni_compiler.h
@@ -42,12 +42,12 @@
namespace art {
namespace compiler_llvm {
-class CompilerLLVM;
+class CompilationUnit;
class IRBuilder;
class JniCompiler {
public:
- JniCompiler(InstructionSet insn_set,
+ JniCompiler(CompilationUnit* cunit,
Compiler const& compiler,
OatCompilationUnit* oat_compilation_unit);
@@ -60,9 +60,8 @@
bool is_static);
private:
- InstructionSet insn_set_;
+ CompilationUnit* cunit_;
Compiler const* compiler_;
- CompilerLLVM* compiler_llvm_;
llvm::Module* module_;
llvm::LLVMContext* context_;
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 8dc81dd..3af60f4 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -17,6 +17,7 @@
#include "method_compiler.h"
#include "backend_types.h"
+#include "compilation_unit.h"
#include "compiler.h"
#include "inferred_reg_category_map.h"
#include "ir_builder.h"
@@ -43,30 +44,29 @@
using namespace runtime_support;
-MethodCompiler::MethodCompiler(InstructionSet insn_set,
+MethodCompiler::MethodCompiler(CompilationUnit* cunit,
Compiler* compiler,
OatCompilationUnit* oat_compilation_unit)
-: insn_set_(insn_set), compiler_(compiler),
- compiler_llvm_(compiler->GetCompilerLLVM()),
- class_linker_(oat_compilation_unit->class_linker_),
- class_loader_(oat_compilation_unit->class_loader_),
- dex_file_(oat_compilation_unit->dex_file_),
- dex_cache_(oat_compilation_unit->dex_cache_),
- code_item_(oat_compilation_unit->code_item_),
- oat_compilation_unit_(oat_compilation_unit),
- method_(dex_cache_->GetResolvedMethod(oat_compilation_unit->method_idx_)),
- method_helper_(method_),
- method_idx_(oat_compilation_unit->method_idx_),
- access_flags_(oat_compilation_unit->access_flags_),
- module_(compiler_llvm_->GetModule()),
- context_(compiler_llvm_->GetLLVMContext()),
- irb_(*compiler_llvm_->GetIRBuilder()), func_(NULL), retval_reg_(NULL),
- basic_block_reg_alloca_(NULL), basic_block_shadow_frame_alloca_(NULL),
- basic_block_reg_zero_init_(NULL), basic_block_reg_arg_init_(NULL),
- basic_blocks_(code_item_->insns_size_in_code_units_),
- basic_block_landing_pads_(code_item_->tries_size_, NULL),
- basic_block_unwind_(NULL), basic_block_unreachable_(NULL),
- shadow_frame_(NULL) {
+ : cunit_(cunit), compiler_(compiler),
+ class_linker_(oat_compilation_unit->class_linker_),
+ class_loader_(oat_compilation_unit->class_loader_),
+ dex_file_(oat_compilation_unit->dex_file_),
+ dex_cache_(oat_compilation_unit->dex_cache_),
+ code_item_(oat_compilation_unit->code_item_),
+ oat_compilation_unit_(oat_compilation_unit),
+ method_(dex_cache_->GetResolvedMethod(oat_compilation_unit->method_idx_)),
+ method_helper_(method_),
+ method_idx_(oat_compilation_unit->method_idx_),
+ access_flags_(oat_compilation_unit->access_flags_),
+ module_(cunit->GetModule()),
+ context_(cunit->GetLLVMContext()),
+ irb_(*cunit->GetIRBuilder()), func_(NULL), retval_reg_(NULL),
+ basic_block_reg_alloca_(NULL), basic_block_shadow_frame_alloca_(NULL),
+ basic_block_reg_zero_init_(NULL), basic_block_reg_arg_init_(NULL),
+ basic_blocks_(code_item_->insns_size_in_code_units_),
+ basic_block_landing_pads_(code_item_->tries_size_, NULL),
+ basic_block_unwind_(NULL), basic_block_unreachable_(NULL),
+ shadow_frame_(NULL) {
}
@@ -3529,7 +3529,13 @@
// Delete the inferred register category map (won't be used anymore)
method_->ResetInferredRegCategoryMap();
- return new CompiledMethod(insn_set_, func_);
+ // Add the memory usage approximation of the compilation unit
+ cunit_->AddMemUsageApproximation(code_item_->insns_size_in_code_units_ * 900);
+ // NOTE: From statistic, the bitcode size is 4.5 times bigger than the
+ // Dex file. Besides, we have to convert the code unit into bytes.
+ // Thus, we got our magic number 9.
+
+ return new CompiledMethod(cunit_->GetInstructionSet(), func_);
}
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 0359fa2..764d892 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -56,14 +56,14 @@
namespace art {
namespace compiler_llvm {
+class CompilationUnit;
class CompilerLLVM;
class IRBuilder;
class MethodCompiler {
private:
- InstructionSet insn_set_;
+ CompilationUnit* cunit_;
Compiler* compiler_;
- compiler_llvm::CompilerLLVM* compiler_llvm_;
ClassLinker* class_linker_;
ClassLoader const* class_loader_;
@@ -101,7 +101,7 @@
public:
- MethodCompiler(InstructionSet insn_set,
+ MethodCompiler(CompilationUnit* cunit,
Compiler* compiler,
OatCompilationUnit* oat_compilation_unit);
diff --git a/src/compiler_llvm/upcall_compiler.cc b/src/compiler_llvm/upcall_compiler.cc
index be4c00d..ec433c2 100644
--- a/src/compiler_llvm/upcall_compiler.cc
+++ b/src/compiler_llvm/upcall_compiler.cc
@@ -16,8 +16,9 @@
#include "upcall_compiler.h"
-#include "compiler.h"
+#include "compilation_unit.h"
#include "compiled_method.h"
+#include "compiler.h"
#include "compiler_llvm.h"
#include "ir_builder.h"
#include "logging.h"
@@ -39,13 +40,9 @@
using namespace runtime_support;
-UpcallCompiler::UpcallCompiler(InstructionSet insn_set,
- Compiler& compiler)
-: insn_set_(insn_set), compiler_(&compiler),
- compiler_llvm_(compiler_->GetCompilerLLVM()),
- module_(compiler_llvm_->GetModule()),
- context_(compiler_llvm_->GetLLVMContext()),
- irb_(*compiler_llvm_->GetIRBuilder()) {
+UpcallCompiler::UpcallCompiler(CompilationUnit* cunit, Compiler& compiler)
+: cunit_(cunit), compiler_(&compiler), module_(cunit_->GetModule()),
+ context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()) {
}
@@ -172,8 +169,16 @@
irb_.CreateRetVoid();
+ // Verify the generated function
llvm::verifyFunction(*func, llvm::PrintMessageAction);
+ // Add the memory usage approximation of the compilation unit
+ cunit_->AddMemUsageApproximation((shorty_size * 3 + 8) * 500);
+ // NOTE: We will emit 3 LLVM instructions per shorty for the argument,
+ // plus 3 for pointer arithmetic, and 5 for code_addr, retval, ret_addr,
+ // store ret_addr, and ret_void. Beside, we guess that we have to use
+ // 50 bytes to represent one LLVM instruction.
+
return new CompiledInvokeStub(func);
}
diff --git a/src/compiler_llvm/upcall_compiler.h b/src/compiler_llvm/upcall_compiler.h
index 426919e..c1e0afc 100644
--- a/src/compiler_llvm/upcall_compiler.h
+++ b/src/compiler_llvm/upcall_compiler.h
@@ -34,19 +34,19 @@
namespace art {
namespace compiler_llvm {
+class CompilationUnit;
class CompilerLLVM;
class IRBuilder;
class UpcallCompiler {
public:
- UpcallCompiler(InstructionSet insn_set, Compiler& compiler);
+ UpcallCompiler(CompilationUnit* cunit, Compiler& compiler);
CompiledInvokeStub* CreateStub(bool is_static, char const* shorty);
private:
- InstructionSet insn_set_;
+ CompilationUnit* cunit_;
Compiler const* compiler_;
- CompilerLLVM* compiler_llvm_;
llvm::Module* module_;
llvm::LLVMContext* context_;
IRBuilder& irb_;
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 9d334ba..d4ed0cc 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -78,6 +78,14 @@
UsageError(" to the file descriptor specified by --oat-fd.");
UsageError(" Example: --oat-location=/data/art-cache/system@app@Calculator.apk.oat");
UsageError("");
+#if defined(ART_USE_LLVM_COMPILER)
+ UsageError(" --elf-file=<file.elf>: specifies the required elf filename.");
+ UsageError(" Example: --elf-file=/system/framework/boot.elf");
+ UsageError("");
+ UsageError(" --bitcode=<file.bc>: specifies the optional bitcode filename.");
+ UsageError(" Example: --bitcode=/system/framework/boot.bc");
+ UsageError("");
+#endif
UsageError(" --image=<file.art>: specifies the output image filename.");
UsageError(" Example: --image=/system/framework/boot.art");
UsageError("");
@@ -187,6 +195,10 @@
bool CreateOatFile(const std::string& boot_image_option,
const std::vector<const DexFile*>& dex_files,
File* oat_file,
+#if defined(ART_USE_LLVM_COMPILER)
+ std::string const& elf_filename,
+ std::string const& bitcode_filename,
+#endif
bool image,
const std::set<std::string>* image_classes) {
// SirtRef and ClassLoader creation needs to come after Runtime::Create
@@ -207,6 +219,12 @@
}
Compiler compiler(instruction_set_, image, thread_count_, support_debugging_, image_classes);
+
+#if defined(ART_USE_LLVM_COMPILER)
+ compiler.SetElfFileName(elf_filename);
+ compiler.SetBitcodeFileName(bitcode_filename);
+#endif
+
compiler.CompileAll(class_loader->get(), dex_files);
if (!OatWriter::Create(oat_file, class_loader->get(), dex_files, compiler)) {
@@ -427,6 +445,10 @@
std::string oat_filename;
std::string oat_location;
int oat_fd = -1;
+#if defined(ART_USE_LLVM_COMPILER)
+ std::string elf_filename;
+ std::string bitcode_filename;
+#endif
const char* image_classes_filename = NULL;
std::string image_filename;
std::string boot_image_filename;
@@ -469,6 +491,12 @@
}
} else if (option.starts_with("--oat-location=")) {
oat_location = option.substr(strlen("--oat-location=")).data();
+#if defined(ART_USE_LLVM_COMPILER)
+ } else if (option.starts_with("--elf-file=")) {
+ elf_filename = option.substr(strlen("--elf-file=")).data();
+ } else if (option.starts_with("--bitcode=")) {
+ bitcode_filename = option.substr(strlen("--bitcode=")).data();
+#endif
} else if (option.starts_with("--image=")) {
image_filename = option.substr(strlen("--image=")).data();
} else if (option.starts_with("--image-classes=")) {
@@ -591,6 +619,23 @@
LOG(INFO) << "dex2oat: " << oat_location;
+#if defined(ART_USE_LLVM_COMPILER)
+ if (elf_filename.empty()) {
+ if (oat_filename.empty()) {
+ LOG(FATAL) << "Both --oat-file and --elf-file are not specified";
+ }
+
+ StringPiece elf_filename_sp(oat_filename);
+ if (elf_filename_sp.ends_with(".oat")) {
+ elf_filename_sp.remove_suffix(strlen(".oat"));
+ }
+
+ elf_filename = elf_filename_sp.ToString() + ".elf";
+ }
+
+ LOG(INFO) << "ELF output: " << elf_filename;
+#endif
+
Runtime::Options options;
options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL)));
std::vector<const DexFile*> boot_class_path;
@@ -643,6 +688,10 @@
if (!dex2oat->CreateOatFile(boot_image_option,
dex_files,
oat_file.get(),
+#if defined(ART_USE_LLVM_COMPILER)
+ elf_filename,
+ bitcode_filename,
+#endif
image,
image_classes.get())) {
LOG(ERROR) << "Failed to create oat file: " << oat_location;
@@ -664,6 +713,12 @@
// We wrote the oat file successfully, and want to keep it.
LOG(INFO) << "Oat file written successfully: " << oat_filename;
+#if defined(ART_USE_LLVM_COMPILER)
+ LOG(INFO) << "ELF file written successfully: " << elf_filename;
+ if (!bitcode_filename.empty()) {
+ LOG(INFO) << "Bitcode file written successfully: " << bitcode_filename;
+ }
+#endif
LOG(INFO) << "Image written successfully: " << image_filename;
return EXIT_SUCCESS;
}
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 99c42f7..a4a4a2c 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -201,6 +201,8 @@
size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t class_def_index,
size_t class_def_method_index, bool is_native, bool is_static,
bool is_direct, uint32_t method_idx, const DexFile* dex_file) {
+
+#if !defined(ART_USE_LLVM_COMPILER)
// derived from CompiledMethod if available
uint32_t code_offset = 0;
uint32_t frame_size_in_bytes = kStackAlignment;
@@ -351,6 +353,8 @@
method->SetOatGcMapOffset(gc_map_offset);
method->SetOatInvokeStubOffset(invoke_stub_offset);
}
+#endif
+
return offset;
}
@@ -502,6 +506,7 @@
size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_class_index,
size_t class_def_method_index, bool is_static,
uint32_t method_idx, const DexFile& dex_file) {
+#if !defined(ART_USE_LLVM_COMPILER)
const CompiledMethod* compiled_method =
compiler_->GetCompiledMethod(Compiler::MethodReference(&dex_file, method_idx));
@@ -679,6 +684,8 @@
}
DCHECK_CODE_OFFSET();
}
+#endif
+
return code_offset;
}