llvm-ndk-cc: driver of NDK llvm ABI

Change-Id: I6b230d089fd7f3b944504b0a1f9a980cc3524aec
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..0e28e75
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,145 @@
+LOCAL_PATH := $(call my-dir)
+LLVM_ROOT_PATH := external/llvm
+CLANG_ROOT_PATH := external/clang
+llvm_static_libs_needed := \
+	libLLVMLinker   \
+	libLLVMipo	\
+	libLLVMBitWriter	\
+	libLLVMBitReader	\
+	libLLVMARMCodeGen	\
+	libLLVMARMAsmPrinter	\
+	libLLVMARMInfo	\
+	libLLVMX86CodeGen	\
+	libLLVMX86AsmPrinter	\
+	libLLVMX86Info	\
+	libLLVMX86Utils	\
+	libLLVMAsmPrinter	\
+	libLLVMSelectionDAG	\
+	libLLVMCodeGen	\
+	libLLVMScalarOpts	\
+	libLLVMInstCombine	\
+	libLLVMTransformUtils	\
+	libLLVMInstrumentation	\
+	libLLVMipa	\
+	libLLVMAnalysis	\
+	libLLVMTarget	\
+	libLLVMMC	\
+	libLLVMMCParser	\
+	libLLVMCore	\
+	libclangFrontend	\
+        libclangDriver \
+	libclangSerialization	\
+	libclangCodeGen	\
+	libclangParse	\
+	libclangSema	\
+	libclangAnalysis	\
+	libclangEdit	\
+	libclangAST	\
+	libclangLex	\
+	libclangBasic	\
+	libLLVMSupport  \
+        libLLVMVectorize
+
+# ========================================================
+# Static library libndkpc for host
+# ========================================================
+include $(CLEAR_VARS)
+include $(CLEAR_TBLGEN_VARS)
+
+include $(CLANG_ROOT_PATH)/clang.mk
+
+LOCAL_MODULE := libndkpc
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += -Wno-sign-promo
+ifneq ($(TARGET_BUILD_VARIANT),eng)
+LOCAL_CFLAGS += -D__DISABLE_ASSERTS
+endif
+
+TBLGEN_TABLES :=    \
+	AttrList.inc	\
+	Attrs.inc	\
+	DeclNodes.inc	\
+	DiagnosticCommonKinds.inc	\
+	DiagnosticFrontendKinds.inc	\
+	DiagnosticSemaKinds.inc	\
+	StmtNodes.inc
+
+LOCAL_SRC_FILES :=	\
+	Compiler.cpp	\
+	Backend.cpp
+
+LOCAL_LDLIBS := -ldl -lpthread
+
+include $(CLANG_HOST_BUILD_MK)
+include $(CLANG_TBLGEN_RULES_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# ========================================================
+# Executable llvm-ndk-cc for host
+# ========================================================
+include $(CLEAR_VARS)
+include $(CLEAR_TBLGEN_VARS)
+
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE := llvm-ndk-cc
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+LOCAL_CFLAGS += -Wno-sign-promo
+ifneq ($(TARGET_BUILD_VARIANT),eng)
+LOCAL_CFLAGS += -D__DISABLE_ASSERTS
+endif
+
+TBLGEN_TABLES :=    \
+	AttrList.inc    \
+	Attrs.inc    \
+	DeclNodes.inc    \
+	DiagnosticCommonKinds.inc   \
+	DiagnosticDriverKinds.inc \
+	DiagnosticFrontendKinds.inc	\
+	DiagnosticSemaKinds.inc	\
+	StmtNodes.inc
+
+LOCAL_SRC_FILES :=	\
+	llvm-ndk-cc.cpp
+
+LOCAL_STATIC_LIBRARIES :=	\
+	libclangDriver libndkpc \
+	$(llvm_static_libs_needed)
+
+ifeq ($(HOST_OS),windows)
+  LOCAL_LDLIBS := -limagehlp -lpsapi
+else
+  LOCAL_LDLIBS := -ldl -lpthread
+endif
+
+include $(CLANG_HOST_BUILD_MK)
+include $(CLANG_TBLGEN_RULES_MK)
+include $(BUILD_HOST_EXECUTABLE)
+
+# ========================================================
+# Executable llvm-ndk-link for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE := llvm-ndk-link
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+LOCAL_SRC_FILES := llvm-ndk-link.cpp
+
+LOCAL_LDLIBS := -ldl -lpthread
+
+LOCAL_STATIC_LIBRARIES := \
+  $(llvm_static_libs_needed)
+
+include $(CLANG_ROOT_PATH)/clang.mk
+include $(CLANG_HOST_BUILD_MK)
+include $(LLVM_ROOT_PATH)/llvm.mk
+include $(LLVM_HOST_BUILD_MK)
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/Backend.cpp b/Backend.cpp
new file mode 100644
index 0000000..57dd54b
--- /dev/null
+++ b/Backend.cpp
@@ -0,0 +1,334 @@
+#include "Backend.h"
+
+#include <cassert>
+#include <string>
+#include <vector>
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+
+#include "clang/CodeGen/ModuleBuilder.h"
+
+#include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+
+#include "llvm/Assembly/PrintModulePass.h"
+
+#include "llvm/Bitcode/ReaderWriter.h"
+
+#include "llvm/CodeGen/RegAllocRegistry.h"
+#include "llvm/CodeGen/SchedulerRegistry.h"
+
+#include "llvm/Instructions.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Metadata.h"
+
+#include "llvm/MC/SubtargetFeature.h"
+
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/InstIterator.h"
+
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Support/TargetRegistry.h"
+
+namespace ndkpc {
+
+void Backend::CreateFunctionPasses() {
+  if (!mpPerFunctionPasses) {
+    mpPerFunctionPasses = new llvm::FunctionPassManager(mpModule);
+    mpPerFunctionPasses->add(new llvm::TargetData(mpModule));
+
+    // FIXME REMOVE
+    //llvm::createStandardFunctionPasses(mpPerFunctionPasses,
+    //                                   mCodeGenOpts.OptimizationLevel);
+    llvm::PassManagerBuilder PMBuilder;
+    PMBuilder.OptLevel = mCodeGenOpts.OptimizationLevel;
+    PMBuilder.populateFunctionPassManager(*mpPerFunctionPasses);
+  }
+  return;
+}
+
+void Backend::CreateModulePasses() {
+  if (!mpPerModulePasses) {
+	  mpPerModulePasses = new llvm::PassManager();
+	  mpPerModulePasses->add(new llvm::TargetData(mpModule));
+
+	  llvm::PassManagerBuilder PMBuilder;
+	  PMBuilder.OptLevel = mCodeGenOpts.OptimizationLevel;
+	  PMBuilder.SizeLevel = mCodeGenOpts.OptimizeSize;
+	  if (mCodeGenOpts.UnitAtATime) {
+		  PMBuilder.DisableUnitAtATime = 0;
+	  } else {
+		  PMBuilder.DisableUnitAtATime = 1;
+	  }
+
+	  if (mCodeGenOpts.UnrollLoops) {
+		  PMBuilder.DisableUnrollLoops = 0;
+	  } else {
+		  PMBuilder.DisableUnrollLoops = 1;
+	  }
+
+	  PMBuilder.DisableSimplifyLibCalls = false;
+	  PMBuilder.populateModulePassManager(*mpPerModulePasses);
+  }
+  return;
+}
+
+bool Backend::CreateCodeGenPasses() {
+  if ((mOT != Compiler::OT_Assembly) && (mOT != Compiler::OT_Object))
+    return true;
+
+  // Now we add passes for code emitting
+  if (mpCodeGenPasses) {
+    return true;
+  } else {
+    mpCodeGenPasses = new llvm::FunctionPassManager(mpModule);
+    mpCodeGenPasses->add(new llvm::TargetData(mpModule));
+  }
+
+  // Create the TargetMachine for generating code.
+  std::string Triple = mpModule->getTargetTriple();
+
+  std::string Error;
+  const llvm::Target* TargetInfo =
+      llvm::TargetRegistry::lookupTarget(Triple, Error);
+  if (TargetInfo == NULL) {
+    mDiags.Report(clang::diag::err_fe_unable_to_create_target) << Error;
+    return false;
+  }
+
+  llvm::TargetOptions Options;
+  Options.NoFramePointerElim = mCodeGenOpts.DisableFPElim;
+
+  // Use hardware FPU.
+  //
+  // FIXME: Need to detect the CPU capability and decide whether to use softfp.
+  // To use softfp, change following 2 lines to
+  //
+  //  llvm::FloatABIType = llvm::FloatABI::Soft;
+  //  llvm::UseSoftFloat = true;
+  Options.FloatABIType = llvm::FloatABI::Hard;
+  Options.UseSoftFloat = false;
+
+  // BCC needs all unknown symbols resolved at compilation time. So we don't
+  // need any relocation model.
+  llvm::Reloc::Model RelocModel = llvm::Reloc::Static;
+
+  // This is set for the linker (specify how large of the virtual addresses we
+  // can access for all unknown symbols.)
+  llvm::CodeModel::Model CodeModel;
+  if (mpModule->getPointerSize() == llvm::Module::Pointer32)
+    CodeModel = llvm::CodeModel::Small;
+  else
+    // The target may have pointer size greater than 32 (e.g. x86_64
+    // architecture) may need large data address model
+    CodeModel = llvm::CodeModel::Medium;
+
+  // Setup feature string
+  std::string FeaturesStr;
+  if (mTargetOpts.CPU.size() || mTargetOpts.Features.size()) {
+    llvm::SubtargetFeatures Features;
+
+    for (std::vector<std::string>::const_iterator
+             I = mTargetOpts.Features.begin(), E = mTargetOpts.Features.end();
+         I != E;
+         I++)
+      Features.AddFeature(*I);
+
+    FeaturesStr = Features.getString();
+  }
+  // Setup optimization level
+  llvm::CodeGenOpt::Level OptLevel = llvm::CodeGenOpt::Default;
+  if (mCodeGenOpts.OptimizationLevel == 0)
+    OptLevel = llvm::CodeGenOpt::None;
+  else if (mCodeGenOpts.OptimizationLevel == 3)
+    OptLevel = llvm::CodeGenOpt::Aggressive;
+
+  llvm::TargetMachine *TM =
+      TargetInfo->createTargetMachine(Triple, mTargetOpts.CPU, FeaturesStr, 
+				      Options, RelocModel, CodeModel, OptLevel);
+
+  // Register scheduler
+  llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler);
+
+  // Register allocation policy:
+  //  createFastRegisterAllocator: fast but bad quality
+  //  createLinearScanRegisterAllocator: not so fast but good quality
+  llvm::RegisterRegAlloc::setDefault((mCodeGenOpts.OptimizationLevel == 0) ?
+                                     llvm::createFastRegisterAllocator :
+                                     llvm::createGreedyRegisterAllocator);
+
+  llvm::TargetMachine::CodeGenFileType CGFT =
+      llvm::TargetMachine::CGFT_AssemblyFile;
+  if (mOT == Compiler::OT_Object)
+    CGFT = llvm::TargetMachine::CGFT_ObjectFile;
+  if (TM->addPassesToEmitFile(*mpCodeGenPasses, FormattedOutStream,
+                              CGFT, OptLevel)) {
+    mDiags.Report(clang::diag::err_fe_unable_to_interface_with_target);
+    return false;
+  }
+
+  return true;
+}
+
+Backend::Backend(const clang::CodeGenOptions &CodeGenOpts,
+                 const clang::TargetOptions &TargetOpts,
+                 clang::DiagnosticsEngine *Diags,
+                 llvm::raw_ostream *OS,
+                 Compiler::OutputType OT)
+    : ASTConsumer(),
+      mCodeGenOpts(CodeGenOpts),
+      mTargetOpts(TargetOpts),
+      mLLVMContext(llvm::getGlobalContext()),
+      mDiags(*Diags),
+      mpModule(NULL),
+      mpOS(OS),
+      mOT(OT),
+      mpGen(NULL),
+      mpPerFunctionPasses(NULL),
+      mpPerModulePasses(NULL),
+      mpCodeGenPasses(NULL) {
+  FormattedOutStream.setStream(*mpOS,
+                               llvm::formatted_raw_ostream::PRESERVE_STREAM);
+  mpGen = CreateLLVMCodeGen(mDiags, "", mCodeGenOpts, mLLVMContext);
+  return;
+}
+
+void Backend::Initialize(clang::ASTContext &Ctx) {
+  mpGen->Initialize(Ctx);
+  mpModule = mpGen->GetModule();
+  return;
+}
+
+bool Backend::HandleTopLevelDecl(clang::DeclGroupRef D) {
+  mpGen->HandleTopLevelDecl(D);
+  return true;
+}
+
+void Backend::HandleTranslationUnit(clang::ASTContext &Ctx) {
+  mpGen->HandleTranslationUnit(Ctx);
+
+  // Here, we complete a translation unit (whole translation unit is now in LLVM
+  // IR). Now, interact with LLVM backend to generate actual machine code (asm
+  // or machine code, whatever.)
+
+  // Silently ignore if we weren't initialized for some reason.
+  if (!mpModule)
+    return;
+
+  llvm::Module *M = mpGen->ReleaseModule();
+  if (!M) {
+    // The module has been released by IR gen on failures, do not double free.
+    mpModule = NULL;
+    return;
+  }
+
+  assert(mpModule == M &&
+              "Unexpected module change during LLVM IR generation");
+
+  // Handle illigal CallSite
+  for (llvm::Module::iterator I = mpModule->begin(), E = mpModule->end();
+       I != E;
+       ++I) {
+    for (llvm::inst_iterator i = llvm::inst_begin(*I), e = llvm::inst_end(*I);
+         i != e;
+         ++i) {
+      if (llvm::CallInst* CallInst = llvm::dyn_cast<llvm::CallInst>(&*i)) {
+        if (CallInst->isInlineAsm()) {
+          // TODO: Should we reflect source location information to diagnostic
+          //       class and show to users?
+          llvm::errs() << "Inline assembly is illigal. Please don't use it." << "\n";
+          exit(1);
+        }
+      }
+    }
+  }
+
+  // Create and run per-function passes
+  CreateFunctionPasses();
+  if (mpPerFunctionPasses) {
+    mpPerFunctionPasses->doInitialization();
+
+    for (llvm::Module::iterator I = mpModule->begin(), E = mpModule->end();
+         I != E;
+         I++)
+      if (!I->isDeclaration())
+        mpPerFunctionPasses->run(*I);
+
+    mpPerFunctionPasses->doFinalization();
+  }
+
+  // Create and run module passes
+  CreateModulePasses();
+  if (mpPerModulePasses)
+    mpPerModulePasses->run(*mpModule);
+
+  switch (mOT) {
+    case Compiler::OT_Assembly:
+    case Compiler::OT_Object: {
+      if (!CreateCodeGenPasses())
+        return;
+
+      mpCodeGenPasses->doInitialization();
+
+      for (llvm::Module::iterator I = mpModule->begin(), E = mpModule->end();
+          I != E;
+          I++)
+        if (!I->isDeclaration())
+          mpCodeGenPasses->run(*I);
+
+      mpCodeGenPasses->doFinalization();
+      break;
+    }
+    case Compiler::OT_LLVMAssembly: {
+      llvm::PassManager *LLEmitPM = new llvm::PassManager();
+      LLEmitPM->add(llvm::createPrintModulePass(&FormattedOutStream));
+      LLEmitPM->run(*mpModule);
+      break;
+    }
+    case Compiler::OT_Bitcode: {
+      llvm::PassManager *BCEmitPM = new llvm::PassManager();
+      BCEmitPM->add(llvm::createBitcodeWriterPass(FormattedOutStream));
+      BCEmitPM->run(*mpModule);
+      break;
+    }
+    case Compiler::OT_Nothing: {
+      return;
+    }
+    default: {
+      assert(false && "Unknown output type");
+    }
+  }
+
+  FormattedOutStream.flush();
+  return;
+}
+
+void Backend::HandleTagDeclDefinition(clang::TagDecl *D) {
+  mpGen->HandleTagDeclDefinition(D);
+  return;
+}
+
+void Backend::CompleteTentativeDefinition(clang::VarDecl *D) {
+  mpGen->CompleteTentativeDefinition(D);
+  return;
+}
+
+Backend::~Backend() {
+  delete mpModule;
+  delete mpGen;
+  delete mpPerFunctionPasses;
+  delete mpPerModulePasses;
+  delete mpCodeGenPasses;
+  return;
+}
+
+}
diff --git a/Backend.h b/Backend.h
new file mode 100644
index 0000000..a6bb7f3
--- /dev/null
+++ b/Backend.h
@@ -0,0 +1,100 @@
+#ifndef _LLVM_NDK_CC_BACKEND_H
+#define _LLVM_NDK_CC_BACKEND_H
+
+#include "clang/AST/ASTConsumer.h"
+
+#include "llvm/PassManager.h"
+
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+
+#include "Compiler.h"
+
+namespace llvm {
+  class formatted_raw_ostream;
+  class LLVMContext;
+  class NamedMDNode;
+  class Module;
+  class PassManager;
+  class FunctionPassManager;
+}
+
+namespace clang {
+  class CodeGenOptions;
+  class CodeGenerator;
+  class DeclGroupRef;
+  class TagDecl;
+  class VarDecl;
+}
+
+namespace ndkpc {
+
+class Backend : public clang::ASTConsumer {
+public:
+  Backend(const clang::CodeGenOptions &CodeGenOpts,
+          const clang::TargetOptions &TargetOpts,
+          clang::DiagnosticsEngine *Diags,
+          llvm::raw_ostream *OS,
+          Compiler::OutputType OT);
+
+  virtual ~Backend();
+
+  // Initialize - This is called to initialize the consumer, providing the
+  // ASTContext.
+  virtual void Initialize(clang::ASTContext &Ctx);
+
+  // HandleTopLevelDecl - Handle the specified top-level declaration.  This is
+  // called by the parser to process every top-level Decl*. Note that D can be
+  // the head of a chain of Decls (e.g. for `int a, b` the chain will have two
+  // elements). Use Decl::getNextDeclarator() to walk the chain.
+  virtual bool HandleTopLevelDecl(clang::DeclGroupRef D);
+
+  // HandleTranslationUnit - This method is called when the ASTs for entire
+  // translation unit have been parsed.
+  virtual void HandleTranslationUnit(clang::ASTContext &Ctx);
+
+  // HandleTagDeclDefinition - This callback is invoked each time a TagDecl
+  // (e.g. struct, union, enum, class) is completed.  This allows the client to
+  // hack on the type, which can occur at any point in the file (because these
+  // can be defined in declspecs).
+  virtual void HandleTagDeclDefinition(clang::TagDecl *D);
+
+  // CompleteTentativeDefinition - Callback invoked at the end of a translation
+  // unit to notify the consumer that the given tentative definition should be
+  // completed.
+  virtual void CompleteTentativeDefinition(clang::VarDecl *D);
+
+private:
+  const clang::CodeGenOptions &mCodeGenOpts;
+  const clang::TargetOptions &mTargetOpts;
+
+  llvm::LLVMContext &mLLVMContext;
+  clang::DiagnosticsEngine &mDiags;
+
+  llvm::Module *mpModule;
+
+  // Output stream
+  llvm::raw_ostream *mpOS;
+  Compiler::OutputType mOT;
+
+  // This helps us translate Clang AST using into LLVM IR
+  clang::CodeGenerator *mpGen;
+
+  // Passes apply on function scope in a translation unit
+  llvm::FunctionPassManager *mpPerFunctionPasses;
+  void CreateFunctionPasses();
+
+  // Passes apply on module scope
+  llvm::PassManager *mpPerModulePasses;
+  void CreateModulePasses();
+
+  // Passes for code emission
+  llvm::FunctionPassManager *mpCodeGenPasses;
+  bool CreateCodeGenPasses();
+
+  llvm::formatted_raw_ostream FormattedOutStream;
+};
+
+}
+
+#endif //  _LLVM_NDK_CC_BACKEND_H
diff --git a/Compiler.cpp b/Compiler.cpp
new file mode 100644
index 0000000..f8bc250
--- /dev/null
+++ b/Compiler.cpp
@@ -0,0 +1,333 @@
+#include "Compiler.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+
+#include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Frontend/DependencyOutputOptions.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/HeaderSearch.h"
+
+#include "clang/Parse/ParseAST.h"
+
+#include "llvm/LLVMContext.h"
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+
+#include "llvm/Bitcode/ReaderWriter.h"
+
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/Path.h"
+
+#include "llvm/Support/TargetSelect.h"
+
+#include "Backend.h"
+
+namespace ndkpc {
+
+static inline llvm::tool_output_file *openOutputFile(const char *OutputFile,
+                                                     unsigned Flags,
+                                                     std::string* Error,
+                                                     clang::DiagnosticsEngine* Diag) {
+  assert((OutputFile != NULL) && (Error != NULL) && (Diag != NULL) &&
+              "Invalid parameter!");
+
+  llvm::tool_output_file *F =
+        new llvm::tool_output_file(OutputFile, *Error, Flags);
+  if (F != NULL)
+    return F;
+
+  // Report error here.
+  Diag->Report(clang::diag::err_fe_error_opening) << OutputFile << *Error;
+
+  return NULL;
+}
+
+void Compiler::LLVMErrorHandler(void *UserData, const std::string &Message) {
+  clang::DiagnosticsEngine* Diags = static_cast<clang::DiagnosticsEngine*>(UserData);
+  Diags->Report(clang::diag::err_fe_error_backend) << Message;
+  exit(1);
+}
+
+void Compiler::createDiagnostic() {
+  mpDiagClient = new clang::TextDiagnosticPrinter(llvm::errs(),
+                                                 clang::DiagnosticOptions());
+  mDiagIDs = new clang::DiagnosticIDs();
+  mDiagnostics = new clang::DiagnosticsEngine(mDiagIDs, mpDiagClient);
+  initDiagnostic();
+  return;
+}
+
+void Compiler::createTarget(const std::string &Triple, const std::string &CPU,
+                         const std::vector<std::string> &Features) {
+  if (!Triple.empty())
+    mTargetOpts.Triple = Triple;
+  else
+    mTargetOpts.Triple = llvm::Triple::normalize(DEFAULT_TARGET_TRIPLE_STRING);
+
+  if (!CPU.empty())
+    mTargetOpts.CPU = CPU;
+
+  if (!Features.empty())
+    mTargetOpts.Features = Features;
+
+  mTarget.reset(clang::TargetInfo::CreateTargetInfo(*mDiagnostics,
+                                                    mTargetOpts));
+
+  return;
+}
+
+void Compiler::createFileManager() {
+  mFileSysOpt.reset(new clang::FileSystemOptions());
+  mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
+}
+
+void Compiler::createSourceManager() {
+  mSourceMgr.reset(new clang::SourceManager(*mDiagnostics, *mFileMgr));
+  return;
+}
+
+void Compiler::createPreprocessor() {
+  clang::HeaderSearch *HS = new clang::HeaderSearch(*mFileMgr,
+						    *mDiagnostics,
+						    mLangOpts,
+						    mTarget.get());
+
+  llvm::OwningPtr<clang::CompilerInstance> Clang(new clang::CompilerInstance());
+   
+  mPP.reset(new clang::Preprocessor(*mDiagnostics,
+                                    mLangOpts,
+                                    mTarget.get(),
+                                    *mSourceMgr,
+                                    *HS,
+				    *Clang,
+                                    /* IILookup */0,
+                                    /* OwnsHeaderSearch = */true,
+                                    /*DelayInitialization=*/true));
+
+  std::vector<clang::DirectoryLookup> SearchList;
+  for (unsigned i = 0, e = mIncludePaths.size(); i != e; i++) {
+    if (const clang::DirectoryEntry *DE =
+            mFileMgr->getDirectory(mIncludePaths[i])) {
+      SearchList.push_back(clang::DirectoryLookup(DE,
+                                                  clang::SrcMgr::C_System,
+                                                  false, /* isUser */
+                                                  false /* isFramework */));
+    }
+  }
+
+  HS->SetSearchPaths(SearchList, 0/* angledDirIdx FIXME CHECK */, 0/* systemDirIdx */, false/* noCurDirSearch */);
+
+  initPreprocessor();
+  return;
+}
+
+void Compiler::createASTContext() {
+  mASTContext.reset(new clang::ASTContext(mLangOpts,
+                                          *mSourceMgr,
+                                          mTarget.get(),
+                                          mPP->getIdentifierTable(),
+                                          mPP->getSelectorTable(),
+                                          mPP->getBuiltinInfo(),
+                                          /* size_reserve = */0,
+                                          /*DelayInitialization=*/true));
+  initASTContext();
+  return;
+}
+
+clang::ASTConsumer
+*Compiler::createBackend(const clang::CodeGenOptions& CodeGenOpts,
+                      llvm::raw_ostream *OS,
+                      OutputType OT) {
+  return new Backend(CodeGenOpts,
+                     mTargetOpts,
+                     mDiagnostics.getPtr(),
+                     OS,
+                     OT);
+}
+
+Compiler::Compiler() : mInitialized(false), mpDiagClient(NULL), mOT(OT_Default) {
+}
+
+void Compiler::injectPreDefined() {
+  typedef std::map<std::string, std::string> SymbolMapTy;
+  for (SymbolMapTy::iterator
+          it = mPreDefinedSymbolMap.begin(), et = mPreDefinedSymbolMap.end();
+       it != et; ++it) {
+    std::string Str = "#define "+it->first+" "+it->second+"\n";
+    mPP->setPredefines(Str);
+  }
+}
+
+void Compiler::init(const std::string &Triple, const std::string &CPU,
+                    const std::vector<std::string> &Features, bool isCXX) {
+  mLangOpts.RTTI = 0;  // Turn off the RTTI information support
+  mLangOpts.NeXTRuntime = 0;   // Turn off the NeXT runtime uses
+  mLangOpts.C99 = 1;
+  if (isCXX) {
+    mLangOpts.CPlusPlus = 1;
+  }
+
+  mCodeGenOpts.OptimizationLevel = 3;  /* -O3 */
+
+  createDiagnostic();
+  llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagnostics.getPtr());
+
+  createTarget(Triple, CPU, Features);
+  createFileManager();
+  createSourceManager();
+
+  mInitialized = true;
+
+  return;
+}
+
+bool Compiler::setInputSource(llvm::StringRef InputFile,
+                              const char *Text,
+                              size_t TextLength) {
+  mInputFileName = InputFile.str();
+
+  // Reset the ID tables if we are reusing the SourceManager
+  mSourceMgr->clearIDTables();
+
+  // Load the source
+  llvm::MemoryBuffer *SB =
+      llvm::MemoryBuffer::getMemBuffer(Text, Text + TextLength);
+  mSourceMgr->createMainFileIDForMemBuffer(SB);
+
+  if (mSourceMgr->getMainFileID().isInvalid()) {
+    mDiagnostics->Report(clang::diag::err_fe_error_reading) << InputFile;
+    return false;
+  }
+  return true;
+}
+
+bool Compiler::setInputSource(llvm::StringRef InputFile) {
+  mInputFileName = InputFile.str();
+
+  mSourceMgr->clearIDTables();
+
+  const clang::FileEntry *File = mFileMgr->getFile(InputFile);
+  if (File)
+    mSourceMgr->createMainFileID(File);
+
+  if (mSourceMgr->getMainFileID().isInvalid()) {
+    mDiagnostics->Report(clang::diag::err_fe_error_reading) << InputFile;
+    return false;
+  }
+
+  return true;
+}
+
+bool Compiler::setOutput(const char *OutputFile) {
+  llvm::sys::Path OutputFilePath(OutputFile);
+  std::string Error;
+  llvm::tool_output_file *OS = NULL;
+
+  switch (mOT) {
+    case OT_Dependency:
+    case OT_Assembly:
+    case OT_LLVMAssembly: {
+      OS = openOutputFile(OutputFile, 0, &Error, mDiagnostics.getPtr());
+      break;
+    }
+    case OT_Nothing: {
+      break;
+    }
+    case OT_Object:
+    case OT_Bitcode: {
+      OS = openOutputFile(OutputFile,
+                          llvm::raw_fd_ostream::F_Binary,
+                          &Error,
+                          mDiagnostics.getPtr());
+      break;
+    }
+    default: {
+      llvm_unreachable("Unknown compiler output type");
+    }
+  }
+
+  if (!Error.empty())
+    return false;
+
+  mOS.reset(OS);
+
+  mOutputFileName = OutputFile;
+
+  return true;
+}
+
+int Compiler::compile() {
+  if (mDiagnostics->hasErrorOccurred())
+    return 1;
+  if (mOS.get() == NULL)
+    return 1;
+
+  // Here is per-compilation needed initialization
+  createPreprocessor();
+  createASTContext();
+
+  mBackend.reset(createBackend(mCodeGenOpts, &mOS->os(), mOT));
+
+  // Inform the diagnostic client we are processing a source file
+  mpDiagClient->BeginSourceFile(mLangOpts, mPP.get());
+
+  if (mLangOpts.CPlusPlus == 1) {
+    mPP->setPredefines("#define __cplusplus\n");
+  }
+
+  this->injectPreDefined();
+
+  // The core of the slang compiler
+  ParseAST(*mPP, mBackend.get(), *mASTContext);
+
+  // Inform the diagnostic client we are done with previous source file
+  mpDiagClient->EndSourceFile();
+
+  // Declare success if no error
+  if (!mDiagnostics->hasErrorOccurred())
+    mOS->keep();
+
+  // The compilation ended, clear
+  mBackend.reset();
+  mASTContext.reset();
+  mPP.reset();
+  mOS.reset();
+
+  return mDiagnostics->hasErrorOccurred() ? 1 : 0;
+}
+
+void Compiler::reset() {
+  mDiagnostics->Reset();
+  return;
+}
+
+Compiler::~Compiler() {
+  llvm::llvm_shutdown();
+  return;
+}
+
+}
diff --git a/Compiler.h b/Compiler.h
new file mode 100644
index 0000000..6209732
--- /dev/null
+++ b/Compiler.h
@@ -0,0 +1,161 @@
+#ifndef _LLVM_NDK_CC_COMPILER_H
+#define _LLVM_NDK_CC_COMPILER_H
+
+#include <cstdio>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetOptions.h"
+
+#include "clang/Frontend/CodeGenOptions.h"
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+  class tool_output_file;
+  class raw_ostream;
+}
+
+namespace clang {
+  class Diagnostic;
+  class DiagnosticClient;
+  class FileManager;
+  class FileSystemOptions;
+  class SourceManager;
+  class Preprocessor;
+  class TargetOptions;
+  class ASTContext;
+  class ASTConsumer;
+  class Backend;
+  class TargetInfo;
+  class TextDiagnosticPrinter;
+}
+
+namespace ndkpc {
+
+#define DEFAULT_TARGET_TRIPLE_STRING "armv7-none-linux-gnueabi"
+
+class Compiler {
+public:
+  typedef enum {
+    OT_Dependency,
+    OT_Assembly,
+    OT_LLVMAssembly,
+    OT_Bitcode,
+    OT_Nothing,
+    OT_Object,
+
+    OT_Default = OT_Bitcode
+  } OutputType;
+
+  Compiler();
+  ~Compiler();
+
+  void init(const std::string &Triple, const std::string &CPU,
+            const std::vector<std::string> &Features,
+            bool isCXX);
+
+  bool setInputSource(llvm::StringRef InputFile, const char *Text,
+                      size_t TextLength);
+
+  bool setInputSource(llvm::StringRef InputFile);
+
+  inline const std::string &getInputFileName() const { return mInputFileName; }
+
+  inline void setIncludePaths(const std::vector<std::string> &IncludePaths) {
+    mIncludePaths = IncludePaths;
+  }
+
+  inline void setPreDefinedSymbol(const std::map<std::string, std::string>& M) {
+    mPreDefinedSymbolMap = M;
+  }
+
+  inline void setOutputType(OutputType OT) { mOT = OT; }
+
+  bool setOutput(const char *OutputFile);
+  inline const std::string &getOutputFileName() const {
+    return mOutputFileName;
+  }
+
+  int compile();
+
+  // Reset the slang compiler state such that it can be reused to compile
+  // another file
+  void reset();
+
+private:
+  clang::LangOptions mLangOpts;
+  clang::CodeGenOptions mCodeGenOpts;
+
+  static void LLVMErrorHandler(void *UserData, const std::string &Message);
+
+  bool mInitialized;
+
+  // The diagnostics engine instance (for status reporting during compilation)
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> mDiagnostics;
+  // The diagnostics id
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> mDiagIDs;
+  // The clients of diagnostics engine. The ownership is taken by the
+  // mDiagnostics after creation.
+  clang::TextDiagnosticPrinter *mpDiagClient;
+  void createDiagnostic();
+
+  // The target being compiled for
+  clang::TargetOptions mTargetOpts;
+  llvm::OwningPtr<clang::TargetInfo> mTarget;
+  void createTarget(const std::string &Triple, const std::string &CPU,
+                    const std::vector<std::string> &Features);
+
+  // Below is for parsing and code generation
+
+  // The file manager (for prepocessor doing the job such as header file search)
+  llvm::OwningPtr<clang::FileManager> mFileMgr;
+  llvm::OwningPtr<clang::FileSystemOptions> mFileSysOpt;
+  void createFileManager();
+
+  // The source manager (responsible for the source code handling)
+  llvm::OwningPtr<clang::SourceManager> mSourceMgr;
+  void createSourceManager();
+
+  // The preprocessor (source code preprocessor)
+  llvm::OwningPtr<clang::Preprocessor> mPP;
+  void createPreprocessor();
+
+  // The AST context (the context to hold long-lived AST nodes)
+  llvm::OwningPtr<clang::ASTContext> mASTContext;
+  void createASTContext();
+
+  // The AST consumer, responsible for code generation
+  llvm::OwningPtr<clang::ASTConsumer> mBackend;
+
+  // Input file name
+  std::string mInputFileName;
+  std::string mOutputFileName;
+
+  OutputType mOT;
+
+  // Output stream
+  llvm::OwningPtr<llvm::tool_output_file> mOS;
+
+  std::vector<std::string> mIncludePaths;
+
+  std::map<std::string, std::string> mPreDefinedSymbolMap;
+  void injectPreDefined();
+
+  void initDiagnostic() {}
+  void initPreprocessor() {}
+  void initASTContext() {}
+
+  clang::ASTConsumer *createBackend(const clang::CodeGenOptions& CodeGenOpts,
+                                    llvm::raw_ostream *OS,
+                                    OutputType OT);
+};
+
+}
+
+#endif // _LLVM_NDK_CC_COMPILER_H
diff --git a/llvm-ndk-cc.cpp b/llvm-ndk-cc.cpp
new file mode 100644
index 0000000..b84b847
--- /dev/null
+++ b/llvm-ndk-cc.cpp
@@ -0,0 +1,102 @@
+#include <cassert>
+#include <cstdlib>
+#include <list>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Option.h"
+#include "clang/Driver/OptTable.h"
+
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/OwningPtr.h"
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+#include "Compiler.h"
+
+// FIXME: Add parameter feature '-D macro=xxx'
+static llvm::cl::opt<std::string>
+InputFilename(llvm::cl::Positional, llvm::cl::Required,
+              llvm::cl::desc("<input file>"));
+
+static llvm::cl::list<std::string>
+HeaderSearchDirs("I", llvm::cl::desc("Header search directory"), llvm::cl::Prefix);
+
+static llvm::cl::list<std::string>
+PreDefinedSymbols("D", llvm::cl::desc("Pre-define symbol"));
+
+static llvm::cl::opt<std::string>
+OutputFilename(llvm::cl::Required, "o", llvm::cl::desc("Override output filename"));
+
+// split "xxx"     => "xxx" ""
+// split "xxx=yyy" => "xxx" "yyy"
+static void splitPreDefinedSymbol(const std::string& In,
+                             std::string& Key, std::string& Value) {
+  size_t FoundPos = In.find("=");
+  if (FoundPos == std::string::npos) {
+    Key = In;
+    Value = "";
+  } else {
+    Key = In.substr(0, FoundPos);
+    Value = In.substr(FoundPos+1, std::string::npos);
+  }
+}
+
+
+int main(int argc, char** argv) {
+  llvm::llvm_shutdown_obj _ShutdownObj;
+  llvm::cl::ParseCommandLineOptions(argc, argv, "P-NDK Compile Tool");
+
+  clang::TextDiagnosticPrinter* DiagClient =
+      new clang::TextDiagnosticPrinter(llvm::errs(), clang::DiagnosticOptions());
+  DiagClient->setPrefix(argv[0]);
+
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>
+      DiagIDs(new clang::DiagnosticIDs());
+  clang::DiagnosticsEngine Diags(DiagIDs, DiagClient, true);
+
+  if (Diags.hasErrorOccurred())
+    return 1;
+
+  std::vector<std::string> IncludePaths;
+  for(unsigned i = 0, e = HeaderSearchDirs.size(); i<e; ++i) {
+    IncludePaths.push_back(HeaderSearchDirs[i]);
+  }
+
+  std::map<std::string, std::string> PreDefinedSymbolMap;
+  for(unsigned i = 0, e = PreDefinedSymbols.size(); i<e; ++i) {
+    std::string Key;
+    std::string Value;
+    splitPreDefinedSymbol(PreDefinedSymbols[i], Key, Value);
+    PreDefinedSymbolMap.insert(
+        std::pair<std::string, std::string>(Key,Value));
+  }
+
+  ndkpc::Compiler Compiler;
+  Compiler.init(std::string(),
+                std::string(),
+                std::vector<std::string>(),
+                llvm::StringRef(InputFilename).endswith(".cpp"));
+  Compiler.setInputSource(InputFilename);
+  Compiler.setIncludePaths(IncludePaths);
+  Compiler.setOutput(OutputFilename.c_str());
+  Compiler.setPreDefinedSymbol(PreDefinedSymbolMap);
+
+  int ret = Compiler.compile();
+  return ret;
+}
diff --git a/llvm-ndk-link.cpp b/llvm-ndk-link.cpp
new file mode 100644
index 0000000..dc9eb8d
--- /dev/null
+++ b/llvm-ndk-link.cpp
@@ -0,0 +1,136 @@
+#include <cassert>
+#include <list>
+#include <string>
+
+#include "llvm/Linker.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/PassManager.h"
+
+#include "llvm/ADT/OwningPtr.h"
+
+#include "llvm/Bitcode/ReaderWriter.h"
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Support/system_error.h"
+
+#include "llvm/Target/TargetData.h"
+
+static llvm::cl::list<std::string>
+InputFilenames(llvm::cl::Positional, llvm::cl::OneOrMore,
+               llvm::cl::desc("<input bitcode files>"));
+
+static llvm::cl::list<std::string>
+OutputFilenames("o", llvm::cl::desc("Override output filename"),
+                llvm::cl::value_desc("output bitcode file"));
+
+
+static llvm::Module* getModuleFromFilename(std::string& Filename,
+                                           llvm::LLVMContext& Ctx,
+                                           std::string& ErrMsg) {
+  llvm::OwningPtr<llvm::MemoryBuffer> MB;
+  llvm::MemoryBuffer::getFile(Filename, MB);
+  llvm::Module* M = llvm::ParseBitcodeFile(MB.get(), Ctx, &ErrMsg);
+  assert(M && ErrMsg);
+  return M;
+}
+
+static void optimizeModule(llvm::Module* M) {
+  llvm::PassManager Passes;
+
+  const std::string &ModuleDataLayout = M->getDataLayout();
+  if (!ModuleDataLayout.empty())
+    if (llvm::TargetData *TD = new llvm::TargetData(ModuleDataLayout))
+      Passes.add(TD);
+
+  Passes.add(llvm::createInternalizePass(true/* AllButMain*/));
+#if 0
+  FIXME REMOVE
+  createStandardLTOPasses(&Passes,
+                          /* Internalize = */false,
+                          /* RunInliner = */true,
+                          /* VerifyEach = */false);
+#endif
+  llvm::PassManagerBuilder PMBuilder;
+  PMBuilder.populateLTOPassManager(Passes, false, true);
+  Passes.run(*M);
+}
+
+static llvm::Module* linkFilesToModule(llvm::cl::list<std::string>& Inputs,
+                                       llvm::LLVMContext& Ctx) {
+  std::string ErrMsg;
+  llvm::Module* M = getModuleFromFilename(Inputs[0], Ctx, ErrMsg);
+  llvm::Linker Linker("llvm-ndk-link", M);
+
+  for (unsigned i=1; i<Inputs.size(); ++i) {
+    llvm::Module* M = getModuleFromFilename(Inputs[i], Ctx, ErrMsg);
+    if (!Linker.LinkInModule(M, &ErrMsg)) {
+      assert(false && ErrMsg);
+    }
+    optimizeModule(M);
+  }
+  M = Linker.releaseModule();
+
+  llvm::PassManager PM;
+  const std::string &ModuleDataLayout = M->getDataLayout();
+  if (!ModuleDataLayout.empty())
+    if (llvm::TargetData *TD = new llvm::TargetData(ModuleDataLayout))
+      PM.add(TD);
+
+#if 0
+  FIXME REMOVE
+  llvm::createStandardFunctionPasses(&PM, 3 /* OptLevel*/);
+  llvm::createStandardModulePasses(&PM,
+                                   3, /* OptimizationLevel */
+                                   true, /* OptimizeSize */
+                                   true, /* UnitAtATime */
+                                   true, /* UnrollLoops */
+                                   true, /* SimplifyLibCalls */
+                                   false, /* HaveExceptions */
+                                   NULL /* InliningPass */);
+#endif
+
+  llvm::PassManagerBuilder PMBuilder;
+  //PMBuilder.OptLevel = 3;
+  //PMBuilder.populateFunctionPassManager(PM);
+
+  PMBuilder.OptLevel = 3;
+  PMBuilder.SizeLevel = true;
+  PMBuilder.DisableUnitAtATime = false;
+  PMBuilder.DisableUnrollLoops = false;
+  PMBuilder.DisableSimplifyLibCalls = false;
+  PMBuilder.populateModulePassManager(PM);
+
+  PM.run(*M);
+  return M;
+}
+
+int main(int argc, char** argv) {
+  llvm::llvm_shutdown_obj _ShutdownObj;
+  llvm::cl::ParseCommandLineOptions(argc, argv, "P-NDK Link Tool");
+
+  llvm::LLVMContext& Ctx = llvm::getGlobalContext();
+  std::string ErrMsg;
+  llvm::raw_fd_ostream FOS(OutputFilenames[0].c_str(), ErrMsg);
+  assert(!FOS.has_error());
+
+  // No need to link (just one file).
+  // Output Directly.
+  if (InputFilenames.size() == 1) {
+    llvm::OwningPtr<llvm::Module> M(getModuleFromFilename(InputFilenames[0],
+                                                           Ctx,
+                                                           ErrMsg));
+    llvm::WriteBitcodeToFile(M.get(), FOS);
+    return 0;
+  }
+
+  llvm::OwningPtr<llvm::Module> M(linkFilesToModule(InputFilenames, Ctx));
+  llvm::WriteBitcodeToFile(M.get(), FOS);
+  assert(!FOS.has_error());
+  return 0;
+}
diff --git a/tests/F_asm/asm.c b/tests/F_asm/asm.c
new file mode 100644
index 0000000..88b450b
--- /dev/null
+++ b/tests/F_asm/asm.c
@@ -0,0 +1,3 @@
+void root() {
+  __asm__("movl %eax, %ebx");
+}
diff --git a/tests/F_asm/asm.stderr.txt.expect b/tests/F_asm/asm.stderr.txt.expect
new file mode 100644
index 0000000..7709dde
--- /dev/null
+++ b/tests/F_asm/asm.stderr.txt.expect
@@ -0,0 +1 @@
+Inline assembly is illigal. Please don't use it.
diff --git a/tests/F_asm/asm.stdout.txt.expect b/tests/F_asm/asm.stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_asm/asm.stdout.txt.expect
diff --git a/tests/P_cxx/c_call.c b/tests/P_cxx/c_call.c
new file mode 100644
index 0000000..981da43
--- /dev/null
+++ b/tests/P_cxx/c_call.c
@@ -0,0 +1,6 @@
+#include <elf.h> // for testing header search
+#include "cxx.h"
+
+int main() {
+  c_interface();
+}
diff --git a/tests/P_cxx/c_call.stderr.txt.expect b/tests/P_cxx/c_call.stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_cxx/c_call.stderr.txt.expect
diff --git a/tests/P_cxx/c_call.stdout.txt.expect b/tests/P_cxx/c_call.stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_cxx/c_call.stdout.txt.expect
diff --git a/tests/P_cxx/cxx.cpp b/tests/P_cxx/cxx.cpp
new file mode 100644
index 0000000..197e91b
--- /dev/null
+++ b/tests/P_cxx/cxx.cpp
@@ -0,0 +1,21 @@
+#include "cxx.h"
+
+void foo() {}
+void foo(int a) {}
+int bar;
+
+namespace {
+  void foo() {}
+  void foo(double a) {}
+  int bar;
+}
+
+namespace kerker {
+  void foo() {}
+  void foo(char* a) {}
+  int bar;
+}
+
+extern "C" void c_interface() {
+  kerker::foo();
+}
diff --git a/tests/P_cxx/cxx.h b/tests/P_cxx/cxx.h
new file mode 100644
index 0000000..2c0a972
--- /dev/null
+++ b/tests/P_cxx/cxx.h
@@ -0,0 +1,9 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void c_interface();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/tests/P_cxx/cxx.stderr.txt.expect b/tests/P_cxx/cxx.stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_cxx/cxx.stderr.txt.expect
diff --git a/tests/P_cxx/cxx.stdout.txt.expect b/tests/P_cxx/cxx.stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_cxx/cxx.stdout.txt.expect
diff --git a/tests/P_define/def.c b/tests/P_define/def.c
new file mode 100644
index 0000000..54a2ece
--- /dev/null
+++ b/tests/P_define/def.c
@@ -0,0 +1,7 @@
+#ifndef kerker
+#define kerker 5566
+#endif
+
+int main() {
+  int i = kerker;
+}
diff --git a/tests/P_define/def.stderr.txt.expect b/tests/P_define/def.stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_define/def.stderr.txt.expect
diff --git a/tests/P_define/def.stdout.txt.expect b/tests/P_define/def.stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_define/def.stdout.txt.expect
diff --git a/tests/P_hello/bar.c b/tests/P_hello/bar.c
new file mode 100644
index 0000000..9cd2ef3
--- /dev/null
+++ b/tests/P_hello/bar.c
@@ -0,0 +1,7 @@
+int bar() {
+  int result = 0;
+  for (int i = 0; i<5566; ++i) {
+    result += 1;
+  }
+  return result;
+}
diff --git a/tests/P_hello/bar.stderr.txt.expect b/tests/P_hello/bar.stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_hello/bar.stderr.txt.expect
diff --git a/tests/P_hello/bar.stdout.txt.expect b/tests/P_hello/bar.stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_hello/bar.stdout.txt.expect
diff --git a/tests/P_hello/hello-llvm.c b/tests/P_hello/hello-llvm.c
new file mode 100644
index 0000000..886afb8
--- /dev/null
+++ b/tests/P_hello/hello-llvm.c
@@ -0,0 +1,6 @@
+int bar();
+
+double hello() {
+  int foobar = bar() + 123;
+  return (double)foobar;
+}
diff --git a/tests/P_hello/hello-llvm.stderr.txt.expect b/tests/P_hello/hello-llvm.stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_hello/hello-llvm.stderr.txt.expect
diff --git a/tests/P_hello/hello-llvm.stdout.txt.expect b/tests/P_hello/hello-llvm.stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_hello/hello-llvm.stdout.txt.expect
diff --git a/tests/P_null_file/null.c b/tests/P_null_file/null.c
new file mode 100644
index 0000000..ac12275
--- /dev/null
+++ b/tests/P_null_file/null.c
@@ -0,0 +1,2 @@
+int i;
+int j;
diff --git a/tests/P_null_file/null.stderr.txt.expect b/tests/P_null_file/null.stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_null_file/null.stderr.txt.expect
diff --git a/tests/P_null_file/null.stdout.txt.expect b/tests/P_null_file/null.stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_null_file/null.stdout.txt.expect
diff --git a/tests/test.py b/tests/test.py
new file mode 100755
index 0000000..40f5878
--- /dev/null
+++ b/tests/test.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python3
+# -*- coding:utf-8 -*-
+"""llvm-ndk-cc Toolchains Test.
+"""
+
+import filecmp
+import glob
+import os
+import subprocess
+import sys
+
+__author__ = 'Nowar Gu'
+
+class Options(object):
+  Verbose = 0
+  Cleanup = 1
+
+def compareFile(Filename):
+  """Compare Filename and Filename.expect for equality."""
+  Actual = Filename
+  Expect = Filename + '.expect'
+
+  if not os.path.isfile(Actual):
+    if Options.Verbose:
+      print('Could not find {0}'.format(Actual))
+    return False
+  if not os.path.isfile(Expect):
+    if Options.Verbose:
+      print('Could not find {0}'.format(Expect))
+    return False
+
+  return filecmp.cmp(Actual, Expect, False)
+
+
+def runFileTest(Filename):
+  """Run test on each file in directory."""
+  Passed = True
+
+  if Options.Verbose != 0:
+    print('\nTesting {0}'.format(Filename))
+
+  Cmd = ('../../../../../out/host/linux-x86/bin/llvm-ndk-cc'
+         ' -I../../../../platforms/android-100/arch-llvm/usr/include'
+         ' -I{0}'.format(os.path.dirname(os.path.realpath(Filename))))
+
+  BaseArgs = Cmd.split()
+  FilenameStubs = Filename.split('.')
+  FileBasename = FilenameStubs[0]
+  Args = BaseArgs
+  Args.append(Filename)
+  Args.append('-o')
+  Args.append(FileBasename + '.bc')
+
+  StdoutFile = open('{0}.stdout.txt'.format(FileBasename), 'w+')
+  StderrFile = open('{0}.stderr.txt'.format(FileBasename), 'w+')
+
+  if Options.Verbose > 1:
+    print('Executing:',end=' ')
+    for Arg in Args:
+      print(Arg,end=' ')
+    print()
+  Ret = subprocess.call(Args, stdout=StdoutFile, stderr=StderrFile)
+  StdoutFile.flush()
+  StderrFile.flush()
+  if Options.Verbose > 1:
+    StdoutFile.seek(0)
+    StderrFile.seek(0)
+    for Line in StdoutFile:
+      print('STDOUT> {0}'.format(Line), end='')
+    for Line in StderrFile:
+      print('STDERR> {0}'.format(Line), end='')
+
+  StdoutFile.close()
+  StderrFile.close()
+  return Ret == 0
+
+
+def runTest(Dirname):
+  """Run an llvm-ndk-cc test from Dirname."""
+  Passed = True
+  os.chdir(Dirname)
+
+  SrcFiles = glob.glob('*.c')
+  SrcFiles.extend(glob.glob('*.cpp'))
+  SrcFiles.sort()
+  FilesPassed = []
+  ResultPassed = True
+  for File in SrcFiles:
+    FileRunPassed = runFileTest(File)
+    FileBasename = File.split('.')[0]
+    if not compareFile('{0}.stdout.txt'.format(FileBasename)):
+      ResultPassed = False
+      if Options.Verbose:
+        print('stdout is different.')
+    if not compareFile('{0}.stderr.txt'.format(FileBasename)):
+      ResultPassed = False
+      if Options.Verbose:
+        print('stderr is different.')
+    FilesPassed.append(FileRunPassed)
+
+  Result = True
+  for FilePassed in FilesPassed:
+    Result = Result and FilePassed
+
+  if Dirname[0:2] == 'F_':
+    if Result == True:
+      Result = False
+      if Options.Verbose:
+        print('Command passed on invalid input.')
+    else:
+      Result = True
+  elif Dirname[0:2] == 'P_':
+    if Result == False:
+      if Options.Verbose:
+        print('Command failed on valid input.')
+  else:
+    if Options.Verbose:
+      print('Test directory name should start with an F or a P.')
+
+  Cmd = ('../../../../../out/host/linux-x86/bin/llvm-ndk-link')
+  Args = Cmd.split()
+  Args.extend(glob.glob('*.bc'))
+  Args.append('-o')
+  Args.append('AllFilesLinked.bc')
+  if Result == True:
+    Ret = subprocess.call(Args)
+    if Ret != 0:
+      Result = False;
+
+    if Options.Verbose > 1:
+      print()
+      print('Executing:',end=' ')
+      for Arg in Args:
+        print(Arg,end=' ')
+      print()
+
+
+  if Options.Cleanup:
+    for File in glob.glob('*.stdout.txt'):
+      os.remove(File)
+    for File in glob.glob('*.stderr.txt'):
+      os.remove(File)
+    for File in glob.glob('*.bc'):
+      os.remove(File)
+
+  os.chdir('..')
+  if Dirname[0:2] == 'F_':
+      return not Result and ResultPassed
+  else:
+    return Result and ResultPassed
+
+
+def showUsage():
+  print('Usage: {0} [Option]... [directory]...'.format(sys.argv[0]))
+  print('llvm-ndk-cc Toolchains Test')
+  print('  -h, --help       Help message')
+  print('  -n, --no-cleanup Do not cleanup after testing')
+  print('  -v, --verbose    Verbose output')
+  return
+
+
+def main():
+  Passed = 0
+  Failed = 0
+  Files = []
+  FailedTests = []
+
+  for Arg in sys.argv[1:]:
+    if Arg in ['-h', '--help']:
+      showUsage()
+      return 0
+    elif Arg in ['-n', '--no-cleanup']:
+      Options.Cleanup = 0
+    elif Arg in ['-v', '--verbose']:
+      Options.Verbose += 1
+    else:
+      if os.path.isdir(Arg):
+        Files.append(Arg)
+      else:
+        print('Invalid test or options: {0}'.format(Arg), file=sys.stderr)
+        return 1
+
+  if not Files:
+    TmpFiles = os.listdir('.')
+    for File in TmpFiles:
+      if os.path.isdir(File) and (File[0:2] == 'F_' or File[0:2] == 'P_'):
+        Files.append(File)
+
+  for Dir in Files:
+    if os.path.isdir(Dir):
+      if runTest(Dir):
+        Passed += 1
+      else:
+        Failed += 1
+        FailedTests.append(Dir)
+
+  print()
+  print('Tests Passed: {0}'.format(Passed))
+  print('Tests Failed: {0}'.format(Failed))
+  if Failed:
+    print('Failures:', end=' ')
+    for Test in FailedTests:
+      print(Test, end=' ')
+    print()
+
+  return Failed != 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())