summaryrefslogtreecommitdiff
path: root/src/compiler_llvm/compilation_unit.cc
diff options
context:
space:
mode:
author Shih-wei Liao <sliao@google.com> 2012-04-20 15:23:36 -0700
committer Shih-wei Liao <sliao@google.com> 2012-04-20 16:34:07 -0700
commitd7726e4629f5e77d0bebdc1a5ffbb27ad7e91a1e (patch)
treed75cae49d08e1798075e309ed699bc5cd71c53d6 /src/compiler_llvm/compilation_unit.cc
parentdbd0034c50362cc1dd8eee144e78e183cc49eaf7 (diff)
Enable separate compilation.
Change-Id: I240665cd02706d11d2f8717b3e3276da435134cb
Diffstat (limited to 'src/compiler_llvm/compilation_unit.cc')
-rw-r--r--src/compiler_llvm/compilation_unit.cc221
1 files changed, 181 insertions, 40 deletions
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index 4eb7fb53cb..9c1f8d0699 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -17,9 +17,11 @@
#include "compilation_unit.h"
#include "compiled_method.h"
+#include "file.h"
#include "instruction_set.h"
#include "ir_builder.h"
#include "logging.h"
+#include "os.h"
#include "runtime_support_builder_arm.h"
#include "runtime_support_builder_x86.h"
@@ -45,6 +47,7 @@
#include <llvm/Support/Debug.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>
@@ -54,12 +57,17 @@
#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/TargetData.h>
#include <llvm/Target/TargetLibraryInfo.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
#include <string>
namespace {
@@ -156,13 +164,176 @@ bool CompilationUnit::WriteBitcodeToFile(const std::string& bitcode_filename) {
return true;
}
+// TODO: Move to scoped_temp_file.h
+class ScopedTempFile {
+ public:
+ ScopedTempFile(const std::string& filename_template)
+ : filename_(filename_template), file_(NULL) {
+ int fd = mkstemp(&filename_[0]);
+ CHECK_NE(-1, fd);
+ file_ = OS::FileFromFd(filename_.c_str(), fd);
+ }
+
+ ~ScopedTempFile() {
+ delete file_;
+ TEMP_FAILURE_RETRY(unlink(filename_.c_str()));
+ }
+
+ int GetFd() {
+ return file_->Fd();
+ }
+
+ const std::string &GetName() const {
+ return filename_;
+ }
+
+ bool ReadToString(std::string &buffer) {
+ off_t file_size = file_->Length();
+ if (file_size <= 0) {
+ buffer.clear();
+ return true;
+ }
+
+ buffer.reserve(file_size);
+ buffer.resize(file_size);
+ return file_->ReadFully(&buffer[0], file_size);
+ }
+
+ private:
+ std::string filename_;
+ File *file_;
+};
bool CompilationUnit::Materialize() {
+ const std::string tmp_file = "/tmp/art-llvm-XXXXXX";
+
+ // Prepare the input
+ ScopedTempFile input(tmp_file);
+ if (input.GetFd() < 0) {
+ PLOG(ERROR) << "Failed to save the module to the file " << tmp_file;
+ return false;
+ }
+
+ // Write the bitcode to the file
+ if (!WriteBitcodeToFile(input.GetName())) {
+ return false;
+ }
+
+ // Prepare the output
+ ScopedTempFile output(tmp_file);
+ if (output.GetFd() < 0) {
+ PLOG(ERROR) << "Failed to prepare the output file " << tmp_file;
+ return false;
+ }
+
+ // Fork a process to do the compilation
+ pid_t pid = fork();
+ if (pid == 0) {
+ // change process groups, so we don't get ripped by ProcessManager
+ setpgid(0, 0);
+
+ // TODO: Should use exec* family instead of invoking a function.
+ // Forward our compilation request to bcc.
+ exit(static_cast<int>(!MaterializeFile(input.GetFd(), output.GetFd(),
+ insn_set_)));
+ } else {
+ if (pid < 0) {
+ LOG(FATAL) << "Failed to fork a process to do the compilation: "
+ << strerror(errno);
+ }
+
+ // Free the resources
+ context_.reset(NULL);
+ irb_.reset(NULL);
+ module_ = NULL;
+
+ int status;
+
+ // Wait for child to finish
+ pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+ if (got_pid != pid) {
+ PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid;
+ return false;
+ }
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ LOG(ERROR) << "Failed to compile the bitcode: " << WEXITSTATUS(status);
+ return false;
+ }
+ }
+
+ // Read the result out from the output file
+ TEMP_FAILURE_RETRY(lseek(output.GetFd(), 0, SEEK_SET));
+ if (!output.ReadToString(elf_image_)) {
+ LOG(ERROR) << "Failed to read the result file";
+ return false;
+ }
+
+ LOG(INFO) << "Compilation Unit: " << elf_idx_ << " (done)";
+
+ return true;
+}
+
+
+void CompilationUnit::RegisterCompiledMethod(const llvm::Function* func,
+ CompiledMethod* compiled_method) {
+ compiled_methods_map_.Put(func, compiled_method);
+}
+
+
+void CompilationUnit::UpdateFrameSizeInBytes(const llvm::Function* func,
+ size_t frame_size_in_bytes) {
+ SafeMap<const llvm::Function*, CompiledMethod*>::iterator iter =
+ compiled_methods_map_.find(func);
+
+ if (iter != compiled_methods_map_.end()) {
+ CompiledMethod* compiled_method = iter->second;
+ compiled_method->SetFrameSizeInBytes(frame_size_in_bytes);
+
+ if (frame_size_in_bytes > 1728u) {
+ LOG(WARNING) << "Huge frame size: " << frame_size_in_bytes
+ << " elf_idx=" << compiled_method->GetElfIndex()
+ << " elf_func_idx=" << compiled_method->GetElfFuncIndex();
+ }
+ }
+}
+
+bool CompilationUnit::MaterializeFile(int input_fd, int output_fd,
+ InstructionSet insn_set) {
+ // Initialize the LLVM first
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllAsmParsers();
+
+ // Read the LLVM module from input_fd
+ llvm::OwningPtr<llvm::MemoryBuffer> memory_buffer;
+ llvm::error_code load_input_err =
+ llvm::MemoryBuffer::getOpenFile(input_fd, "<art-llvm-module>",
+ memory_buffer);
+
+ if (load_input_err) {
+ LOG(ERROR) << "Failed to load input for compiler into memory: "
+ << load_input_err.message();
+ return false;
+ }
+
+ // It's safe to use the global context now
+ std::string load_module_errmsg;
+ llvm::Module *module = ParseBitcodeFile(memory_buffer.get(),
+ llvm::getGlobalContext(),
+ &load_module_errmsg);
+ if (module == NULL) {
+ LOG(ERROR) << "Failed to load LLVM module to compiler: "
+ << load_module_errmsg;
+ return false;
+ }
+
// Lookup the LLVM target
char const* target_triple = NULL;
char const* target_attr = NULL;
- switch (insn_set_) {
+ switch (insn_set) {
case kThumb2:
target_triple = "thumb-none-linux-gnueabi";
target_attr = "+thumb2,+neon,+neonfp,+vfp3";
@@ -170,6 +341,7 @@ bool CompilationUnit::Materialize() {
case kArm:
target_triple = "armv7-none-linux-gnueabi";
+ // TODO: Fix for Xoom.
target_attr = "+v7,+neon,+neonfp,+vfp3";
break;
@@ -184,7 +356,7 @@ bool CompilationUnit::Materialize() {
break;
default:
- LOG(FATAL) << "Unknown instruction set: " << insn_set_;
+ LOG(FATAL) << "Unknown instruction set: " << insn_set;
}
std::string errmsg;
@@ -209,7 +381,6 @@ bool CompilationUnit::Materialize() {
CHECK(target_machine != NULL) << "Failed to create target machine";
-
// Add target data
llvm::TargetData const* target_data = target_machine->getTargetData();
@@ -218,7 +389,7 @@ bool CompilationUnit::Materialize() {
pm.add(new llvm::TargetData(*target_data));
// FunctionPassManager for optimization pass
- llvm::FunctionPassManager fpm(module_);
+ llvm::FunctionPassManager fpm(module);
fpm.add(new llvm::TargetData(*target_data));
// Add optimization pass
@@ -232,7 +403,7 @@ bool CompilationUnit::Materialize() {
// Add passes to emit ELF image
{
llvm::formatted_raw_ostream formatted_os(
- *(new llvm::raw_string_ostream(elf_image_)), true);
+ *(new llvm::raw_fd_ostream(output_fd, /* shouldClose */false)), true);
// Ask the target to add backend passes as necessary.
if (target_machine->addPassesToEmitFile(pm,
@@ -243,55 +414,25 @@ bool CompilationUnit::Materialize() {
return false;
}
+ // FIXME: Unable to run the UpdateFrameSizePass pass since it tries to
+ // update the value reside in the different address space.
// Add pass to update the frame_size_in_bytes_
- pm.add(new ::UpdateFrameSizePass(this));
+ //pm.add(new ::UpdateFrameSizePass(this));
// Run the per-function optimization
fpm.doInitialization();
- for (llvm::Module::iterator F = module_->begin(), E = module_->end();
+ 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_);
+ pm.run(*module);
}
- LOG(INFO) << "Compilation Unit: " << elf_idx_ << " (done)";
-
- // Free the resources
- context_.reset(NULL);
- irb_.reset(NULL);
- module_ = NULL;
-
return true;
}
-
-void CompilationUnit::RegisterCompiledMethod(const llvm::Function* func,
- CompiledMethod* compiled_method) {
- compiled_methods_map_.Put(func, compiled_method);
-}
-
-
-void CompilationUnit::UpdateFrameSizeInBytes(const llvm::Function* func,
- size_t frame_size_in_bytes) {
- SafeMap<const llvm::Function*, CompiledMethod*>::iterator iter =
- compiled_methods_map_.find(func);
-
- if (iter != compiled_methods_map_.end()) {
- CompiledMethod* compiled_method = iter->second;
- compiled_method->SetFrameSizeInBytes(frame_size_in_bytes);
-
- if (frame_size_in_bytes > 1728u) {
- LOG(WARNING) << "Huge frame size: " << frame_size_in_bytes
- << " elf_idx=" << compiled_method->GetElfIndex()
- << " elf_func_idx=" << compiled_method->GetElfFuncIndex();
- }
- }
-}
-
-
} // namespace compiler_llvm
} // namespace art