Merge "Add approx_atan function" into jb-mr1-dev
diff --git a/include/bcc/AndroidBitcode/ABCCompiler.h b/include/bcc/AndroidBitcode/ABCCompiler.h
new file mode 100644
index 0000000..91b8009
--- /dev/null
+++ b/include/bcc/AndroidBitcode/ABCCompiler.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef BCC_ABC_COMPILER_H
+#define BCC_ABC_COMPILER_H
+
+#include "bcc/Compiler.h"
+
+namespace bcc {
+
+class ABCCompilerDriver;
+
+class ABCCompiler : public Compiler {
+private:
+  const ABCCompilerDriver &mDriver;
+
+public:
+  ABCCompiler(const ABCCompilerDriver &pDriver) : mDriver(pDriver) { }
+
+  virtual ~ABCCompiler() { }
+
+private:
+  virtual bool beforeAddCodeGenPasses(Script &pScript, llvm::PassManager &pPM);
+};
+
+} // end namespace bcc
+
+#endif // BCC_ABC_COMPILER_H
diff --git a/include/bcc/AndroidBitcode/ABCCompilerDriver.h b/include/bcc/AndroidBitcode/ABCCompilerDriver.h
index 0fa38fe..5f5ad7f 100644
--- a/include/bcc/AndroidBitcode/ABCCompilerDriver.h
+++ b/include/bcc/AndroidBitcode/ABCCompilerDriver.h
@@ -17,6 +17,7 @@
 #ifndef BCC_ABC_COMPILER_DRIVER_H
 #define BCC_ABC_COMPILER_DRIVER_H
 
+#include "bcc/AndroidBitcode/ABCCompiler.h"
 #include "bcc/BCCContext.h"
 #include "bcc/Compiler.h"
 #include "bcc/Linker.h"
@@ -25,13 +26,14 @@
 
 namespace bcc {
 
+class ABCExpandVAArgPass;
 class CompilerConfig;
 class LinkerConfig;
 
 class ABCCompilerDriver {
 private:
   BCCContext mContext;
-  Compiler mCompiler;
+  ABCCompiler mCompiler;
   Linker mLinker;
 
   CompilerConfig *mCompilerConfig;
@@ -50,11 +52,33 @@
   bool link(const Script &pScript, const std::string &input_relocatable,
             int pOutputFd);
 
-public:
-  ABCCompilerDriver(const std::string &pTriple,
-                    const std::string &pAndroidSysroot);
+protected:
+  virtual const char **getNonPortableList() const {
+    return NULL;
+  }
 
-  ~ABCCompilerDriver();
+public:
+  virtual ABCExpandVAArgPass *createExpandVAArgPass() const = 0;
+
+protected:
+  ABCCompilerDriver(const std::string &pTriple);
+
+public:
+  static ABCCompilerDriver *Create(const std::string &pTriple);
+
+  virtual ~ABCCompilerDriver();
+
+  inline const std::string &getAndroidSysroot() const {
+    return mAndroidSysroot;
+  }
+
+  inline void setAndroidSysroot(const std::string &pAndroidSysroot) {
+    mAndroidSysroot = pAndroidSysroot;
+  }
+
+  inline const std::string &getTriple() const {
+    return mTriple;
+  }
 
   // Compile the bitcode and link the shared object
   bool build(int pInputFd, int pOutputFd);
diff --git a/include/bcc/AndroidBitcode/ABCExpandVAArgPass.h b/include/bcc/AndroidBitcode/ABCExpandVAArgPass.h
new file mode 100644
index 0000000..162eeb2
--- /dev/null
+++ b/include/bcc/AndroidBitcode/ABCExpandVAArgPass.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef BCC_ABC_EXPAND_VAARG_PASS_H
+#define BCC_ABC_EXPAND_VAARG_PASS_H
+
+#include <llvm/Pass.h>
+
+namespace llvm {
+  class Function;
+  class Instruction;
+  class LLVMContext;
+  class Value;
+} // end llvm namespace
+
+namespace bcc {
+
+/*
+ * This pass expands va_arg LLVM instruction generated from llvm-ndk-cc.
+ *
+ * LLVM backend does not yet fully support va_arg on many targets. Also,
+ * it does not currently support va_arg with aggregate types on any target.
+ * Therefore, each target should implement its own verion of
+ * ABCExpandVAArg::expandVAArg to expand va_arg.
+ */
+
+class ABCExpandVAArgPass : public llvm::FunctionPass {
+private:
+  static char ID;
+
+protected:
+  llvm::LLVMContext *mContext;
+
+private:
+  virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) = 0;
+
+public:
+  ABCExpandVAArgPass() : llvm::FunctionPass(ID), mContext(NULL) { }
+
+  virtual bool runOnFunction(llvm::Function &pFunc);
+};
+
+} // end bcc namespace
+
+#endif // BCC_ABC_EXPAND_VAARG_PASS_H
diff --git a/include/bcc/Config/Config.h b/include/bcc/Config/Config.h
index 9dd2a93..0331ae0 100644
--- a/include/bcc/Config/Config.h
+++ b/include/bcc/Config/Config.h
@@ -57,6 +57,7 @@
 #endif
 
 #define DEFAULT_ARM_TRIPLE_STRING      "armv7-none-linux-gnueabi"
+#define DEFAULT_THUMB_TRIPLE_STRING    "thumbv7-none-linux-gnueabi"
 #define DEFAULT_MIPS_TRIPLE_STRING     "mipsel-none-linux-gnueabi"
 #define DEFAULT_X86_TRIPLE_STRING      "i686-unknown-linux"
 #define DEFAULT_X86_64_TRIPLE_STRING   "x86_64-unknown-linux"
diff --git a/lib/AndroidBitcode/ABCCompiler.cpp b/lib/AndroidBitcode/ABCCompiler.cpp
new file mode 100644
index 0000000..8393d48
--- /dev/null
+++ b/lib/AndroidBitcode/ABCCompiler.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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/ABCCompiler.h"
+
+#include <llvm/Module.h>
+#include <llvm/PassManager.h>
+#include <llvm/Target/TargetData.h>
+#include <llvm/Target/TargetMachine.h>
+
+#include "bcc/AndroidBitcode/ABCCompilerDriver.h"
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
+#include "bcc/Script.h"
+#include "bcc/Source.h"
+
+
+namespace bcc {
+
+bool ABCCompiler::beforeAddCodeGenPasses(Script &pScript,
+                                         llvm::PassManager &pPM) {
+  llvm::PassManager pm;
+  llvm::Module &module = pScript.getSource().getModule();
+  const llvm::TargetMachine &tm = getTargetMachine();
+  llvm::TargetData *target_data =
+    new (std::nothrow) llvm::TargetData(*(tm.getTargetData()));
+
+  if (target_data == NULL) {
+    return false;
+  }
+
+  pm.add(target_data);
+  pm.add(mDriver.createExpandVAArgPass());
+  pm.run(module);
+
+  return true;
+}
+
+} // namespace bcc
diff --git a/lib/AndroidBitcode/ABCCompilerDriver.cpp b/lib/AndroidBitcode/ABCCompilerDriver.cpp
index 84b6583..4eb33e6 100644
--- a/lib/AndroidBitcode/ABCCompilerDriver.cpp
+++ b/lib/AndroidBitcode/ABCCompilerDriver.cpp
@@ -17,8 +17,10 @@
 #include "bcc/AndroidBitcode/ABCCompilerDriver.h"
 
 #include <llvm/Module.h>
+#include <llvm/Pass.h>
 #include <llvm/Support/MemoryBuffer.h>
 #include <llvm/Support/raw_ostream.h>
+#include <mcld/Config/Config.h>
 
 #include "bcc/Config/Config.h"
 #include "bcc/Script.h"
@@ -30,15 +32,22 @@
 #include "bcc/Support/TargetLinkerConfigs.h"
 #include "bcc/Support/TargetCompilerConfigs.h"
 
-#include "mcld/Config/Config.h"
+#if defined(PROVIDE_ARM_CODEGEN)
+# include "ARM/ARMABCCompilerDriver.h"
+#endif
+#if defined(PROVIDE_MIPS_CODEGEN)
+# include "Mips/MipsABCCompilerDriver.h"
+#endif
+#if defined(PROVIDE_X86_CODEGEN)
+# include "X86/X86ABCCompilerDriver.h"
+#endif
 
 namespace bcc {
 
-ABCCompilerDriver::ABCCompilerDriver(const std::string &pTriple,
-                                     const std::string &pAndroidSysroot)
-  : mContext(), mCompiler(), mLinker(),
+ABCCompilerDriver::ABCCompilerDriver(const std::string &pTriple)
+  : mContext(), mCompiler(*this), mLinker(),
     mCompilerConfig(NULL), mLinkerConfig(NULL),
-    mTriple(pTriple), mAndroidSysroot(pAndroidSysroot) {
+    mTriple(pTriple), mAndroidSysroot("/") {
 }
 
 ABCCompilerDriver::~ABCCompilerDriver() {
@@ -95,16 +104,13 @@
   // 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");
+  const char **non_portable_func = getNonPortableList();
+  if (non_portable_func != NULL) {
+    while (*non_portable_func != NULL) {
+      mLinkerConfig->addPortable(*non_portable_func);
+      non_portable_func++;
+    }
+  }
 
   // -shared
   mLinkerConfig->setShared(true);
@@ -211,6 +217,44 @@
 
 //------------------------------------------------------------------------------
 
+ABCCompilerDriver *ABCCompilerDriver::Create(const std::string &pTriple) {
+  std::string error;
+  const llvm::Target *target =
+      llvm::TargetRegistry::lookupTarget(pTriple, error);
+
+  if (target == NULL) {
+    ALOGE("Unsupported target '%s' (detail: %s)!", pTriple.c_str(),
+          error.c_str());
+    return NULL;
+  }
+
+  switch (llvm::Triple::getArchTypeForLLVMName(target->getName())) {
+#if defined(PROVIDE_ARM_CODEGEN)
+    case llvm::Triple::arm:
+    case llvm::Triple::thumb: {
+      return new ARMABCCompilerDriver(pTriple);
+    }
+#endif
+#if defined(PROVIDE_MIPS_CODEGEN)
+    case llvm::Triple::mipsel: {
+      return new MipsABCCompilerDriver(pTriple);
+    }
+#endif
+#if defined(PROVIDE_X86_CODEGEN)
+    case llvm::Triple::x86: {
+      return new X86ABCCompilerDriver(pTriple);
+    }
+#endif
+    default: {
+      ALOGE("Unknown architecture '%s' supplied in %s!", target->getName(),
+            pTriple.c_str());
+      break;
+    }
+  }
+
+  return NULL;
+}
+
 bool ABCCompilerDriver::build(int pInputFd, int pOutputFd) {
   //===--------------------------------------------------------------------===//
   // Prepare the input.
diff --git a/lib/AndroidBitcode/ABCExpandVAArgPass.cpp b/lib/AndroidBitcode/ABCExpandVAArgPass.cpp
new file mode 100644
index 0000000..7b89ced
--- /dev/null
+++ b/lib/AndroidBitcode/ABCExpandVAArgPass.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef BCC_ABC_EXPAND_VAARG_H
+#define BCC_ABC_EXPAND_VAARG_H
+
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
+
+#include <llvm/Instructions.h>
+#include <llvm/Support/InstIterator.h>
+
+namespace bcc {
+
+char ABCExpandVAArgPass::ID = 0;
+
+bool ABCExpandVAArgPass::runOnFunction(llvm::Function &pFunc) {
+  bool changed = false;
+
+  mContext = &pFunc.getContext();
+
+  // process va_arg inst
+  for (llvm::inst_iterator inst = llvm::inst_begin(pFunc),
+          inst_end = llvm::inst_end(pFunc); inst != inst_end; inst++) {
+    if (inst->getOpcode() == llvm::Instruction::VAArg) {
+      llvm::Value *v = expandVAArg(&*inst);
+      inst->replaceAllUsesWith(v);
+      inst->eraseFromParent();
+      changed = true;
+      continue;
+    }
+  }
+  return changed;
+}
+
+} // end bcc namespace
+
+#endif // BCC_ABC_EXPAND_VAARG_H
diff --git a/lib/AndroidBitcode/ARM/ARMABCCompilerDriver.h b/lib/AndroidBitcode/ARM/ARMABCCompilerDriver.h
new file mode 100644
index 0000000..29f4f0a
--- /dev/null
+++ b/lib/AndroidBitcode/ARM/ARMABCCompilerDriver.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef BCC_ARM_ABC_COMPILER_DRIVER_H
+#define BCC_ARM_ABC_COMPILER_DRIVER_H
+
+#include "bcc/AndroidBitcode/ABCCompilerDriver.h"
+
+namespace bcc {
+
+class ARMABCCompilerDriver : public ABCCompilerDriver {
+public:
+  ARMABCCompilerDriver(const std::string &pTriple)
+      : ABCCompilerDriver(pTriple) { }
+
+  virtual ~ARMABCCompilerDriver() { }
+
+private:
+  virtual ABCExpandVAArgPass *createExpandVAArgPass() const;
+};
+
+} // end namespace bcc
+
+#endif // BCC_ARM_ABC_COMPILER_DRIVER_H
diff --git a/lib/AndroidBitcode/ARM/ARMABCExpandVAArg.cpp b/lib/AndroidBitcode/ARM/ARMABCExpandVAArg.cpp
new file mode 100644
index 0000000..7f154af
--- /dev/null
+++ b/lib/AndroidBitcode/ARM/ARMABCExpandVAArg.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 <llvm/ADT/Triple.h>
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/Instructions.h>
+#include <llvm/IRBuilder.h>
+#include <llvm/Module.h>
+#include <llvm/Pass.h>
+#include <llvm/Type.h>
+#include <llvm/Target/TargetData.h>
+
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
+
+#include "ARM/ARMABCCompilerDriver.h"
+
+namespace {
+
+class ARMABCExpandVAArg : public bcc::ABCExpandVAArgPass {
+public:
+  virtual const char *getPassName() const {
+    return "ARM LLVM va_arg Instruction Expansion Pass";
+  }
+
+private:
+  // Derivative work from external/clang/lib/CodeGen/TargetInfo.cpp.
+  llvm::Value *expandVAArg(llvm::Instruction *pInst) {
+    llvm::Type *pty = pInst->getType();
+    llvm::Type *ty = pty->getContainedType(0);
+    llvm::Value *va_list_addr = pInst->getOperand(0);
+    llvm::IRBuilder<> builder(pInst);
+    const llvm::TargetData *td = getAnalysisIfAvailable<llvm::TargetData>();
+
+    llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
+    llvm::Type *bpp = bp->getPointerTo(0);
+
+    llvm::Value *va_list_addr_bpp =
+        builder.CreateBitCast(va_list_addr, bpp, "ap");
+    llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
+    // Handle address alignment for type alignment > 32 bits.
+    uint64_t ty_align = td->getABITypeAlignment(ty);
+
+    if (ty_align > 4) {
+      assert((ty_align & (ty_align - 1)) == 0 &&
+        "Alignment is not power of 2!");
+      llvm::Value *addr_as_int =
+        builder.CreatePtrToInt(addr, llvm::Type::getInt32Ty(*mContext));
+      addr_as_int = builder.CreateAdd(addr_as_int,
+        builder.getInt32(ty_align-1));
+      addr_as_int = builder.CreateAnd(addr_as_int,
+        builder.getInt32(~(ty_align-1)));
+      addr = builder.CreateIntToPtr(addr_as_int, bp);
+    }
+    llvm::Value *addr_typed = builder.CreateBitCast(addr, pty);
+
+    uint64_t offset = llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty)/8, 4);
+    llvm::Value *next_addr = builder.CreateGEP(addr,
+      llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), offset),
+      "ap.next");
+    builder.CreateStore(next_addr, va_list_addr_bpp);
+    return addr_typed;
+  }
+
+};
+
+} // end anonymous namespace
+
+namespace bcc {
+
+ABCExpandVAArgPass *ARMABCCompilerDriver::createExpandVAArgPass() const {
+  return new ARMABCExpandVAArg();
+}
+
+} // end namespace bcc
diff --git a/lib/AndroidBitcode/Android.mk b/lib/AndroidBitcode/Android.mk
index 1abc7b2..806202c 100644
--- a/lib/AndroidBitcode/Android.mk
+++ b/lib/AndroidBitcode/Android.mk
@@ -22,8 +22,22 @@
 #=====================================================================
 
 libbcc_androidbitcode_SRC_FILES := \
+  ABCCompiler.cpp \
+  ABCExpandVAArgPass.cpp \
   ABCCompilerDriver.cpp
 
+libbcc_arm_androidbitcode_SRC_FILES := \
+  ARM/ARMABCExpandVAArg.cpp
+
+libbcc_mips_androidbitcode_SRC_FILES := \
+  Mips/MipsABCCompilerDriver.cpp \
+  Mips/MipsABCExpandVAArg.cpp
+
+libbcc_x86_androidbitcode_SRC_FILES := \
+  X86/X86ABCCompilerDriver.cpp \
+  X86/X86ABCExpandVAArg.cpp
+
+
 #=====================================================================
 # Device Static Library: libbccAndroidBitcode
 #=====================================================================
@@ -33,9 +47,22 @@
 LOCAL_MODULE := libbccAndroidBitcode
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-
 LOCAL_SRC_FILES := $(libbcc_androidbitcode_SRC_FILES)
 
+ifeq ($(TARGET_ARCH),arm)
+  LOCAL_SRC_FILES += $(libbcc_arm_androidbitcode_SRC_FILES)
+else
+  ifeq ($(TARGET_ARCH),mips)
+    LOCAL_SRC_FILES += $(libbcc_mips_androidbitcode_SRC_FILES)
+  else
+    ifeq ($(TARGET_ARCH),x86) # We don't support x86-64 right now
+      LOCAL_SRC_FILES += $(libbcc_x86_androidbitcode_SRC_FILES)
+    else
+      $(error Unsupported TARGET_ARCH $(TARGET_ARCH))
+    endif
+  endif
+endif
+
 include $(LIBBCC_DEVICE_BUILD_MK)
 include $(LIBBCC_GEN_CONFIG_MK)
 include $(MCLD_DEVICE_BUILD_MK)
@@ -50,8 +77,11 @@
 LOCAL_MODULE := libbccAndroidBitcode
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-
-LOCAL_SRC_FILES := $(libbcc_androidbitcode_SRC_FILES)
+LOCAL_SRC_FILES := \
+  $(libbcc_androidbitcode_SRC_FILES) \
+  $(libbcc_arm_androidbitcode_SRC_FILES) \
+  $(libbcc_mips_androidbitcode_SRC_FILES) \
+  $(libbcc_x86_androidbitcode_SRC_FILES) \
 
 include $(LIBBCC_HOST_BUILD_MK)
 include $(LIBBCC_GEN_CONFIG_MK)
diff --git a/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.cpp b/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.cpp
new file mode 100644
index 0000000..54b9d61
--- /dev/null
+++ b/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "Mips/MipsABCCompilerDriver.h"
+
+namespace {
+
+static const char *MipsNonPortableList[] = {
+  "stat",
+  "fstat",
+  "lstat",
+  "fstatat",
+  "socket",
+  "setsockopt",
+  "getsockopt",
+  "open",
+  "mmap",
+  "ioctl",
+
+  NULL  // NUL-terminator
+};
+
+} // end anonymous namespace
+
+namespace bcc {
+
+const char **MipsABCCompilerDriver::getNonPortableList() const {
+  return MipsNonPortableList;
+}
+
+} // end namespace bcc
diff --git a/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.h b/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.h
new file mode 100644
index 0000000..7cfc34f
--- /dev/null
+++ b/lib/AndroidBitcode/Mips/MipsABCCompilerDriver.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef BCC_MIPS_ABC_COMPILER_DRIVER_H
+#define BCC_MIPS_ABC_COMPILER_DRIVER_H
+
+#include "bcc/AndroidBitcode/ABCCompilerDriver.h"
+
+namespace bcc {
+
+class MipsABCCompilerDriver : public ABCCompilerDriver {
+public:
+  MipsABCCompilerDriver(const std::string &pTriple)
+      : ABCCompilerDriver(pTriple) { }
+
+  virtual ~MipsABCCompilerDriver() { }
+
+private:
+  virtual const char **getNonPortableList() const;
+
+  virtual ABCExpandVAArgPass *createExpandVAArgPass() const;
+};
+
+} // end namespace bcc
+
+#endif // BCC_MIPS_ABC_COMPILER_DRIVER_H
diff --git a/lib/AndroidBitcode/Mips/MipsABCExpandVAArg.cpp b/lib/AndroidBitcode/Mips/MipsABCExpandVAArg.cpp
new file mode 100644
index 0000000..495cef4
--- /dev/null
+++ b/lib/AndroidBitcode/Mips/MipsABCExpandVAArg.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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 <llvm/ADT/Triple.h>
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/Instructions.h>
+#include <llvm/IRBuilder.h>
+#include <llvm/Module.h>
+#include <llvm/Pass.h>
+#include <llvm/Type.h>
+#include <llvm/Target/TargetData.h>
+
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
+
+#include "Mips/MipsABCCompilerDriver.h"
+
+namespace {
+
+class MipsABCExpandVAArg : public bcc::ABCExpandVAArgPass {
+public:
+  virtual const char *getPassName() const {
+    return "Mips LLVM va_arg Instruction Expansion Pass";
+  }
+
+private:
+  // Derivative work from external/clang/lib/CodeGen/TargetInfo.cpp.
+  virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) {
+    llvm::Type *pty = pInst->getType();
+    llvm::Type *ty = pty->getContainedType(0);
+    llvm::Value *va_list_addr = pInst->getOperand(0);
+    llvm::IRBuilder<> builder(pInst);
+    const llvm::TargetData *td = getAnalysisIfAvailable<llvm::TargetData>();
+
+    llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
+    llvm::Type *bpp = bp->getPointerTo(0);
+    llvm::Value *va_list_addr_bpp = builder.CreateBitCast(va_list_addr,
+                                                          bpp, "ap");
+    llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
+    int64_t type_align = td->getABITypeAlignment(ty);
+    llvm::Value *addr_typed;
+    llvm::IntegerType *int_ty = llvm::Type::getInt32Ty(*mContext);
+
+    if (type_align > 4) {
+      llvm::Value *addr_as_int = builder.CreatePtrToInt(addr, int_ty);
+      llvm::Value *inc = llvm::ConstantInt::get(int_ty, type_align - 1);
+      llvm::Value *mask = llvm::ConstantInt::get(int_ty, -type_align);
+      llvm::Value *add_v = builder.CreateAdd(addr_as_int, inc);
+      llvm::Value *and_v = builder.CreateAnd(add_v, mask);
+      addr_typed = builder.CreateIntToPtr(and_v, pty);
+    }
+    else {
+      addr_typed = builder.CreateBitCast(addr, pty);
+    }
+
+    llvm::Value *aligned_addr = builder.CreateBitCast(addr_typed, bp);
+    type_align = std::max((unsigned)type_align, (unsigned) 4);
+    uint64_t offset =
+      llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty) / 8, type_align);
+    llvm::Value *next_addr =
+      builder.CreateGEP(aligned_addr, llvm::ConstantInt::get(int_ty, offset),
+                        "ap.next");
+    builder.CreateStore(next_addr, va_list_addr_bpp);
+
+    return addr_typed;
+  }
+
+};
+
+} // end anonymous namespace
+
+namespace bcc {
+
+ABCExpandVAArgPass *MipsABCCompilerDriver::createExpandVAArgPass() const {
+  return new MipsABCExpandVAArg();
+}
+
+} // end namespace bcc
diff --git a/lib/AndroidBitcode/X86/X86ABCCompilerDriver.cpp b/lib/AndroidBitcode/X86/X86ABCCompilerDriver.cpp
new file mode 100644
index 0000000..171da7c
--- /dev/null
+++ b/lib/AndroidBitcode/X86/X86ABCCompilerDriver.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 "X86/X86ABCCompilerDriver.h"
+
+namespace {
+
+static const char *X86NonPortableList[] = {
+  "stat",
+  "fstat",
+  "lstat",
+  "fstatat",
+  "open",
+  "ioctl",
+  "fcntl",
+  "epoll_ctl",
+  "epoll_wait",
+
+  NULL  // NUL-terminator
+};
+
+} // end anonymous namespace
+
+namespace bcc {
+
+const char **X86ABCCompilerDriver::getNonPortableList() const {
+  return X86NonPortableList;
+}
+
+} // end namespace bcc
diff --git a/lib/AndroidBitcode/X86/X86ABCCompilerDriver.h b/lib/AndroidBitcode/X86/X86ABCCompilerDriver.h
new file mode 100644
index 0000000..af52866
--- /dev/null
+++ b/lib/AndroidBitcode/X86/X86ABCCompilerDriver.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef BCC_X86_ABC_COMPILER_DRIVER_H
+#define BCC_X86_ABC_COMPILER_DRIVER_H
+
+#include "bcc/AndroidBitcode/ABCCompilerDriver.h"
+
+namespace bcc {
+
+class X86ABCCompilerDriver : public ABCCompilerDriver {
+public:
+  X86ABCCompilerDriver(const std::string &pTriple)
+      : ABCCompilerDriver(pTriple) { }
+
+  virtual ~X86ABCCompilerDriver() { }
+
+private:
+  virtual const char **getNonPortableList() const;
+
+  virtual ABCExpandVAArgPass *createExpandVAArgPass() const;
+};
+
+} // end namespace bcc
+
+#endif // BCC_X86_ABC_COMPILER_DRIVER_H
diff --git a/lib/AndroidBitcode/X86/X86ABCExpandVAArg.cpp b/lib/AndroidBitcode/X86/X86ABCExpandVAArg.cpp
new file mode 100644
index 0000000..6d9acbc
--- /dev/null
+++ b/lib/AndroidBitcode/X86/X86ABCExpandVAArg.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 <llvm/ADT/Triple.h>
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/Instructions.h>
+#include <llvm/IRBuilder.h>
+#include <llvm/Module.h>
+#include <llvm/Pass.h>
+#include <llvm/Type.h>
+#include <llvm/Target/TargetData.h>
+
+#include "bcc/AndroidBitcode/ABCExpandVAArgPass.h"
+
+#include "X86/X86ABCCompilerDriver.h"
+
+namespace {
+
+class X86ABCExpandVAArg : public bcc::ABCExpandVAArgPass {
+public:
+  virtual const char *getPassName() const {
+    return "X86 LLVM va_arg Instruction Expansion Pass";
+  }
+
+private:
+  // Derivative work from external/clang/lib/CodeGen/TargetInfo.cpp.
+  virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) {
+    llvm::Type *pty = pInst->getType();
+    llvm::Type *ty = pty->getContainedType(0);
+    llvm::Value *va_list_addr = pInst->getOperand(0);
+    llvm::IRBuilder<> builder(pInst);
+    const llvm::TargetData *td = getAnalysisIfAvailable<llvm::TargetData>();
+
+    llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
+    llvm::Type *bpp = bp->getPointerTo(0);
+    llvm::Value *va_list_addr_bpp = builder.CreateBitCast(va_list_addr,
+                                                          bpp, "ap");
+    llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
+
+    llvm::Value *addr_typed = builder.CreateBitCast(addr, pty);
+
+    // X86-32 stack type alignment is always 4.
+    uint64_t offset = llvm::RoundUpToAlignment(td->getTypeSizeInBits(ty)/8, 4);
+    llvm::Value *next_addr = builder.CreateGEP(addr,
+      llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), offset),
+      "ap.next");
+    builder.CreateStore(next_addr, va_list_addr_bpp);
+
+    return addr_typed;
+  }
+
+}; // end X86ABCExpandVAArg
+
+} // end anonymous namespace
+
+namespace bcc {
+
+ABCExpandVAArgPass *X86ABCCompilerDriver::createExpandVAArgPass() const {
+  return new X86ABCExpandVAArg();
+}
+
+} // end namespace bcc
diff --git a/libbcc-device-build.mk b/libbcc-device-build.mk
index bc250b8..8673be8 100644
--- a/libbcc-device-build.mk
+++ b/libbcc-device-build.mk
@@ -45,6 +45,9 @@
   ifeq ($(ARCH_ARM_HAVE_NEON),true)
     LOCAL_CFLAGS += -DARCH_ARM_HAVE_NEON
   endif
+  ifeq ($(ARCH_ARM_HAVE_THUMB_SUPPORT),true)
+    LOCAL_CFLAGS += -DARCH_ARM_HAVE_THUMB_SUPPORT
+  endif
 else
   ifeq ($(TARGET_ARCH),mips)
     LOCAL_CFLAGS += -DFORCE_MIPS_CODEGEN
diff --git a/tools/abcc/Main.cpp b/tools/abcc/Main.cpp
index 7fe99eb..44ceadd 100644
--- a/tools/abcc/Main.cpp
+++ b/tools/abcc/Main.cpp
@@ -120,8 +120,19 @@
 
 static bool Build(int input_fd, int output_fd,
                   const char *triple, const char *sysroot) {
-  ABCCompilerDriver driver(triple, sysroot);
-  return driver.build(input_fd, output_fd);;
+  ABCCompilerDriver *driver = ABCCompilerDriver::Create(triple);
+
+  if (driver == NULL) {
+    return false;
+  }
+
+  driver->setAndroidSysroot(sysroot);
+
+  bool build_result = driver->build(input_fd, output_fd);;
+
+  delete driver;
+
+  return build_result;
 }
 
 static int ProcessFromFd(const char *input, const char *output,