Add a bitcode compiler driver. BUG=6886348.

ABCCompilerDriver takes bitcode as input and use
bcc::Compiler and bcc::Linker to generate a shared object.

Change-Id: Ie4d92e125bd0c694ebe152bdc128cfa2d95acb4f
diff --git a/lib/AndroidBitcode/ABCCompilerDriver.cpp b/lib/AndroidBitcode/ABCCompilerDriver.cpp
new file mode 100644
index 0000000..84b6583
--- /dev/null
+++ b/lib/AndroidBitcode/ABCCompilerDriver.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright 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 "bcc/AndroidBitcode/ABCCompilerDriver.h"
+
+#include <llvm/Module.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/raw_ostream.h>
+
+#include "bcc/Config/Config.h"
+#include "bcc/Script.h"
+#include "bcc/Source.h"
+#include "bcc/Support/CompilerConfig.h"
+#include "bcc/Support/LinkerConfig.h"
+#include "bcc/Support/Log.h"
+#include "bcc/Support/OutputFile.h"
+#include "bcc/Support/TargetLinkerConfigs.h"
+#include "bcc/Support/TargetCompilerConfigs.h"
+
+#include "mcld/Config/Config.h"
+
+namespace bcc {
+
+ABCCompilerDriver::ABCCompilerDriver(const std::string &pTriple,
+                                     const std::string &pAndroidSysroot)
+  : mContext(), mCompiler(), mLinker(),
+    mCompilerConfig(NULL), mLinkerConfig(NULL),
+    mTriple(pTriple), mAndroidSysroot(pAndroidSysroot) {
+}
+
+ABCCompilerDriver::~ABCCompilerDriver() {
+  delete mCompilerConfig;
+  delete mLinkerConfig;
+}
+
+bool ABCCompilerDriver::configCompiler() {
+  if (mCompilerConfig != NULL) {
+    return true;
+  }
+
+  mCompilerConfig = new (std::nothrow) CompilerConfig(mTriple);
+  if (mCompilerConfig == NULL) {
+    ALOGE("Out of memory when create the compiler configuration!");
+    return false;
+  }
+
+  // Set PIC mode for relocatables.
+  mCompilerConfig->setRelocationModel(llvm::Reloc::PIC_);
+
+  // Set optimization level to -O1.
+  mCompilerConfig->setOptimizationLevel(llvm::CodeGenOpt::Less);
+
+  Compiler::ErrorCode result = mCompiler.config(*mCompilerConfig);
+
+  if (result != Compiler::kSuccess) {
+    ALOGE("Failed to configure the compiler! (detail: %s)",
+          Compiler::GetErrorString(result));
+    return false;
+  }
+
+  return true;
+}
+
+bool ABCCompilerDriver::configLinker() {
+  if (mLinkerConfig != NULL) {
+    return true;
+  }
+
+  mLinkerConfig = new (std::nothrow) LinkerConfig(mTriple);
+  if (mLinkerConfig == NULL) {
+    ALOGE("Out of memory when create the linker configuration!");
+    return false;
+  }
+
+  // FIXME: how can we get the soname if input/output is file descriptor?
+  mLinkerConfig->setSOName("");
+
+  mLinkerConfig->setDyld("/system/bin/linker");
+  mLinkerConfig->setSysRoot(mAndroidSysroot);
+  mLinkerConfig->addSearchDir("=/system/lib");
+
+  // Add non-portable function list. For each function X, linker will rename
+  // it to X_portable. And X_portable" is implemented in libportable to solve
+  // portable issues.
+  mLinkerConfig->addPortable("stat");
+  mLinkerConfig->addPortable("fstat");
+  mLinkerConfig->addPortable("lstat");
+  mLinkerConfig->addPortable("fstatat");
+  mLinkerConfig->addPortable("socket");
+  mLinkerConfig->addPortable("setsockopt");
+  mLinkerConfig->addPortable("getsockopt");
+  mLinkerConfig->addPortable("epoll_event");
+  mLinkerConfig->addPortable("epoll_ctl");
+  mLinkerConfig->addPortable("epoll_wait");
+
+  // -shared
+  mLinkerConfig->setShared(true);
+
+  // -Bsymbolic.
+  mLinkerConfig->setBsymbolic(true);
+
+  // Config the linker.
+  Linker::ErrorCode result = mLinker.config(*mLinkerConfig);
+  if (result != Linker::kSuccess) {
+    ALOGE("Failed to configure the linker! (%s)",
+          Linker::GetErrorString(result));
+    return false;
+  }
+
+  return true;
+}
+
+//------------------------------------------------------------------------------
+
+Script *ABCCompilerDriver::prepareScript(int pInputFd) {
+  Source *source = Source::CreateFromFd(mContext, pInputFd);
+  if (source == NULL) {
+    ALOGE("Failed to load LLVM module from file descriptor `%d'", pInputFd);
+    return NULL;
+  }
+
+  Script *script = new (std::nothrow) Script(*source);
+  if (script == NULL) {
+    ALOGE("Out of memory when create script for file descriptor `%d'!",
+          pInputFd);
+    delete source;
+    return NULL;
+  }
+
+  return script;
+}
+
+bool ABCCompilerDriver::compile(Script &pScript, llvm::raw_ostream &pOutput) {
+  // Config the compiler.
+  if (!configCompiler()) {
+    return false;
+  }
+
+  // Run the compiler.
+  Compiler::ErrorCode result = mCompiler.compile(pScript, pOutput);
+  if (result != Compiler::kSuccess) {
+    ALOGE("Fatal error during compilation (%s)!",
+          Compiler::GetErrorString(result));
+    return false;
+  }
+
+  return true;
+}
+
+bool ABCCompilerDriver::link(const Script &pScript,
+                             const std::string &input_relocatable,
+                             int pOutputFd) {
+  // Config the linker.
+  if (!configLinker()) {
+    return false;
+  }
+
+  // Prepare output file.
+  Linker::ErrorCode result = mLinker.setOutput(pOutputFd);
+
+  if (result != Linker::kSuccess) {
+    ALOGE("Failed to open the output file! (file descriptor `%d': %s)",
+          pOutputFd, Linker::GetErrorString(result));
+    return false;
+  }
+
+  mLinker.addObject(mAndroidSysroot + "/system/lib/crtbegin_so.o");
+
+  // Prepare the relocatables.
+  //
+  // FIXME: Ugly const_cast here.
+  mLinker.addObject(const_cast<char *>(input_relocatable.data()),
+                    input_relocatable.size());
+
+  // Read dependent library list.
+  const Source &source = pScript.getSource();
+  for (llvm::Module::lib_iterator lib_iter = source.getModule().lib_begin(),
+          lib_end = source.getModule().lib_end(); lib_iter != lib_end;
+       ++lib_iter) {
+    mLinker.addNameSpec(*lib_iter);
+  }
+
+  // TODO: Refactor libbcc/runtime/ to libcompilerRT.so and use it.
+  mLinker.addNameSpec("bcc");
+
+  mLinker.addObject(mAndroidSysroot + "/system/lib/crtend_so.o");
+
+  // Perform linking.
+  result = mLinker.link();
+  if (result != Linker::kSuccess) {
+    ALOGE("Failed to link the shared object (detail: %s)",
+          Linker::GetErrorString(result));
+    return false;
+  }
+
+  return true;
+}
+
+//------------------------------------------------------------------------------
+
+bool ABCCompilerDriver::build(int pInputFd, int pOutputFd) {
+  //===--------------------------------------------------------------------===//
+  // Prepare the input.
+  //===--------------------------------------------------------------------===//
+  Script *script = prepareScript(pInputFd);
+  if (script == NULL) {
+    return false;
+  }
+
+  //===--------------------------------------------------------------------===//
+  // Prepare the output.
+  //===--------------------------------------------------------------------===//
+  std::string output_relocatable;
+  llvm::raw_ostream *output =
+      new (std::nothrow) llvm::raw_string_ostream(output_relocatable);
+  if (output == NULL) {
+    ALOGE("Failed to prepare the output for compile the input from %d into "
+          "relocatable object!", pInputFd);
+    delete script;
+    return false;
+  }
+
+  //===--------------------------------------------------------------------===//
+  // Compile.
+  //===--------------------------------------------------------------------===//
+  if (!compile(*script, *output)) {
+    delete output;
+    delete script;
+    return false;
+  }
+
+  //===--------------------------------------------------------------------===//
+  // Close the output.
+  //===--------------------------------------------------------------------===//
+  delete output;
+
+  //===--------------------------------------------------------------------===//
+  // Link.
+  //===--------------------------------------------------------------------===//
+  if (!link(*script, output_relocatable, pOutputFd)) {
+    delete script;
+    return false;
+  }
+
+  //===--------------------------------------------------------------------===//
+  // Clean up.
+  //===--------------------------------------------------------------------===//
+  delete script;
+
+  return true;
+}
+
+} // namespace bcc