diff options
| author | 2012-04-20 15:23:36 -0700 | |
|---|---|---|
| committer | 2012-04-20 16:34:07 -0700 | |
| commit | d7726e4629f5e77d0bebdc1a5ffbb27ad7e91a1e (patch) | |
| tree | d75cae49d08e1798075e309ed699bc5cd71c53d6 /src/compiler_llvm/compilation_unit.cc | |
| parent | dbd0034c50362cc1dd8eee144e78e183cc49eaf7 (diff) | |
Enable separate compilation.
Change-Id: I240665cd02706d11d2f8717b3e3276da435134cb
Diffstat (limited to 'src/compiler_llvm/compilation_unit.cc')
| -rw-r--r-- | src/compiler_llvm/compilation_unit.cc | 221 |
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 |