[Beignet] [PATCH] Change clang system call to libclang api call.

Yang Rong rong.r.yang at intel.com
Mon May 20 21:45:56 PDT 2013


The original call clang command directly as frontend. The implement is not very flexible.
I change to call libclang apis, now support both clang 3.1 and clang 3.2.
Now still write the intermediate to the file, for code simply.
Also fix llvm 3.1 build errors for my vector scalarize commit.

Signed-off-by: Yang Rong <rong.r.yang at intel.com>
---
 CMake/FindLLVM.cmake                  |   27 ++++++++-
 backend/src/CMakeLists.txt            |    1 +
 backend/src/backend/program.cpp       |  103 ++++++++++++++++++++++++++-------
 backend/src/llvm/llvm_gen_backend.cpp |    7 +--
 backend/src/llvm/llvm_scalarize.cpp   |   10 ++--
 5 files changed, 116 insertions(+), 32 deletions(-)

diff --git a/CMake/FindLLVM.cmake b/CMake/FindLLVM.cmake
index c06b8a4..b320639 100644
--- a/CMake/FindLLVM.cmake
+++ b/CMake/FindLLVM.cmake
@@ -8,7 +8,7 @@
 # LLVM_FOUND       - True if llvm found.
 if (LLVM_INSTALL_DIR)
   find_program(LLVM_CONFIG_EXECUTABLE NAMES llvm-config-32 llvm-config-3.2 llvm-config DOC "llvm-config executable" PATHS ${LLVM_INSTALL_DIR} NO_DEFAULT_PATH)
-else (LLVM_INSTALL_DIR)                                                                
+else (LLVM_INSTALL_DIR)
   find_program(LLVM_CONFIG_EXECUTABLE NAMES llvm-config-32 llvm-config-3.2 llvm-config DOC "llvm-config executable")
 endif (LLVM_INSTALL_DIR)
 
@@ -66,3 +66,28 @@ execute_process(
   OUTPUT_VARIABLE LLVM_MODULE_LIBS
   OUTPUT_STRIP_TRAILING_WHITESPACE
 )
+
+macro(add_one_lib name)
+  FIND_LIBRARY(CLANG_LIB
+    NAMES ${name}
+    PATHS ${LLVM_LIBRARY_DIR} )
+  set(CLANG_LIBRARIES ${CLANG_LIBRARIES} ${CLANG_LIB})
+	unset(CLANG_LIB CACHE)
+endmacro()
+
+#Assume clang lib path same as llvm lib path
+add_one_lib("clangFrontend")
+add_one_lib("clangSerialization")
+add_one_lib("clangDriver")
+add_one_lib("clangCodeGen")
+add_one_lib("clangSema")
+add_one_lib("clangStaticAnalyzerFrontend")
+add_one_lib("clangStaticAnalyzerCheckers")
+add_one_lib("clangStaticAnalyzerCore")
+add_one_lib("clangAnalysis")
+add_one_lib("clangEdit")
+add_one_lib("clangAST")
+add_one_lib("clangParse")
+add_one_lib("clangSema")
+add_one_lib("clangLex")
+add_one_lib("clangBasic")
diff --git a/backend/src/CMakeLists.txt b/backend/src/CMakeLists.txt
index 183517a..a0fe198 100644
--- a/backend/src/CMakeLists.txt
+++ b/backend/src/CMakeLists.txt
@@ -116,6 +116,7 @@ target_link_libraries(
                       ${DRM_INTEL_LIBRARY}
                       ${DRM_LIBRARY}
                       ${OPENGL_LIBRARIES}
+                      ${CLANG_LIBRARIES}
                       ${LLVM_MODULE_LIBS}
                       ${CMAKE_THREAD_LIBS_INIT}
                       ${CMAKE_DL_LIBS})
diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp
index c46c681..6816a13 100644
--- a/backend/src/backend/program.cpp
+++ b/backend/src/backend/program.cpp
@@ -46,6 +46,23 @@
 #define LLVM_VERSION_MINOR 0
 #endif /* !defined(LLVM_VERSION_MINOR) */
 
+#include <clang/CodeGen/CodeGenAction.h>
+#include <clang/Frontend/CompilerInstance.h>
+#include <clang/Frontend/CompilerInvocation.h>
+#if LLVM_VERSION_MINOR <= 1
+#include <clang/Frontend/DiagnosticOptions.h>
+#else
+#include <clang/Basic/DiagnosticOptions.h>
+#endif  /* LLVM_VERSION_MINOR <= 1 */
+#include <clang/Frontend/TextDiagnosticPrinter.h>
+#include <clang/Basic/TargetInfo.h>
+#include <clang/Basic/TargetOptions.h>
+#include <llvm/ADT/IntrusiveRefCntPtr.h>
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/Module.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/Support/raw_ostream.h>
+
 namespace gbe {
 
   Kernel::Kernel(const std::string &name) :
@@ -104,6 +121,71 @@ namespace gbe {
     GBE_SAFE_DELETE(program);
   }
 
+  static void buildModuleFromSource(const char* input, const char* output) {
+    // Arguments to pass to the clang frontend
+    vector<const char *> args;
+    args.push_back("-emit-llvm");
+    args.push_back("-O3");
+    args.push_back("-triple");
+    args.push_back("nvptx");
+    args.push_back(input);
+
+    // The compiler invocation needs a DiagnosticsEngine so it can report problems
+#if LLVM_VERSION_MINOR <= 1
+    args.push_back("-triple");
+    args.push_back("ptx32");
+
+    clang::TextDiagnosticPrinter *DiagClient =
+                             new clang::TextDiagnosticPrinter(llvm::errs(), clang::DiagnosticOptions());
+    llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new clang::DiagnosticIDs());
+    clang::DiagnosticsEngine Diags(DiagID, DiagClient);
+#else
+    args.push_back("-ffp-contract=off");
+    args.push_back("-triple");
+    args.push_back("nvptx");
+
+    llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts = new clang::DiagnosticOptions();
+    clang::TextDiagnosticPrinter *DiagClient =
+                             new clang::TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+    llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new clang::DiagnosticIDs());
+    clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+#endif /* LLVM_VERSION_MINOR <= 1 */
+
+    // Create the compiler invocation
+    llvm::OwningPtr<clang::CompilerInvocation> CI(new clang::CompilerInvocation);
+    clang::CompilerInvocation::CreateFromArgs(*CI,
+                                              &args[0],
+                                              &args[0] + args.size(),
+                                              Diags);
+
+    // Create the compiler instance
+    clang::CompilerInstance Clang;
+    Clang.setInvocation(CI.take());
+    // Get ready to report problems
+    Clang.createDiagnostics(args.size(), &args[0]);
+    if (!Clang.hasDiagnostics())
+      return;
+
+    // Set Language
+    clang::LangOptions & lang_opts = Clang.getLangOpts();
+    lang_opts.OpenCL = 1;
+
+    // Create an action and make the compiler instance carry it out
+    llvm::OwningPtr<clang::CodeGenAction> Act(new clang::EmitLLVMOnlyAction());
+    if (!Clang.ExecuteAction(*Act))
+      return;
+
+    llvm::Module *module = Act->takeModule();
+
+    std::string ErrorInfo;
+    llvm::raw_fd_ostream OS(output, ErrorInfo,llvm::raw_fd_ostream::F_Binary);
+    //still write to temp file for code simply, otherwise need add another function.
+    //because gbe_program_new_from_llvm also be used by cl_program_create_from_llvm, can't be removed
+    //TODO: Pass module to llvmToGen, if use module, should return Act and use OwningPtr out of this funciton
+    llvm::WriteBitcodeToFile(module, OS);
+    OS.close();
+  }
+
   extern std::string ocl_stdlib_str;
   extern std::string ocl_common_defines_str;
   static gbe_program programNewFromSource(const char *source,
@@ -124,26 +206,7 @@ namespace gbe {
     fwrite(source, strlen(source), 1, clFile);
     fclose(clFile);
 
-    // Now compile the code to llvm using clang
-#if LLVM_VERSION_MINOR <= 1
-    std::string compileCmd = "clang -x cl -fno-color-diagnostics -emit-llvm -O3 -ccc-host-triple ptx32 -c ";
-#else
-    std::string compileCmd = "clang -ffp-contract=off -emit-llvm -O3 -target nvptx -x cl -c ";
-#endif /* LLVM_VERSION_MINOR <= 1 */
-    compileCmd += clName;
-    compileCmd += " ";
-    if(options)
-      compileCmd += options;
-    compileCmd += " -o ";
-    compileCmd += llName;
-
-    // Open a pipe and compile from here. Using Clang API instead is better
-    FILE *pipe = popen(compileCmd.c_str(), "r");
-    FATAL_IF (pipe == NULL, "Unable to run extern compilation command");
-    char msg[256];
-    while (fgets(msg, sizeof(msg), pipe))
-      std::cout << msg;
-    pclose(pipe);
+    buildModuleFromSource(clName.c_str(), llName.c_str());
     remove(clName.c_str());
 
     // Now build the program from llvm
diff --git a/backend/src/llvm/llvm_gen_backend.cpp b/backend/src/llvm/llvm_gen_backend.cpp
index deda687..d9a773a 100644
--- a/backend/src/llvm/llvm_gen_backend.cpp
+++ b/backend/src/llvm/llvm_gen_backend.cpp
@@ -853,11 +853,8 @@ namespace gbe
       // Insert a new register for each function argument
 #if LLVM_VERSION_MINOR <= 1
       const AttrListPtr &PAL = F.getAttributes();
-      uint32_t argID = 1; // Start at one actually
-      for (; I != E; ++I, ++argID) {
-#else
-      for (; I != E; ++I, ++argID) {
 #endif /* LLVM_VERSION_MINOR <= 1 */
+      for (; I != E; ++I, ++argID) {
         const std::string &argName = I->getName().str();
         Type *type = I->getType();
 
@@ -892,7 +889,7 @@ namespace gbe
           PointerType *pointerType = dyn_cast<PointerType>(type);
           // By value structure
 #if LLVM_VERSION_MINOR <= 1
-          if (PAL.paramHasAttr(argID, Attribute::ByVal)) {
+          if (PAL.paramHasAttr(argID+1, Attribute::ByVal)) {
 #else
           if (I->hasByValAttr()) {
 #endif /* LLVM_VERSION_MINOR <= 1 */
diff --git a/backend/src/llvm/llvm_scalarize.cpp b/backend/src/llvm/llvm_scalarize.cpp
index f71401f..ef431f2 100644
--- a/backend/src/llvm/llvm_scalarize.cpp
+++ b/backend/src/llvm/llvm_scalarize.cpp
@@ -71,7 +71,11 @@
 #include "llvm/IntrinsicInst.h"
 #include "llvm/Module.h"
 #include "llvm/Pass.h"
+#if LLVM_VERSION_MINOR <= 1
+#include "llvm/Support/IRBuilder.h"
+#else
 #include "llvm/IRBuilder.h"
+#endif /* LLVM_VERSION_MINOR <= 1 */
 #include "llvm/Support/CallSite.h"
 #include "llvm/Support/CFG.h"
 #include "llvm/Support/raw_ostream.h"
@@ -730,13 +734,7 @@ namespace gbe {
 
     Function::arg_iterator I = F.arg_begin(), E = F.arg_end();
 
-#if LLVM_VERSION_MINOR <= 1
-    const AttrListPtr &PAL = F.getAttributes();
-    uint32_t argID = 1; // Start at one actually
-    for (; I != E; ++I, ++argID) {
-#else
     for (; I != E; ++I) {
-#endif /* LLVM_VERSION_MINOR <= 1 */
       Type *type = I->getType();
 
       if(type->isVectorTy())
-- 
1.7.9.5



More information about the Beignet mailing list