From: Junyan He <junyan...@linux.intel.com>

The source building process will first find the
PCH version based on the CL option and then do
the conformance check. If passed, the PCH will
be used and if failed, it will fallback to building
from scratch.

Signed-off-by: Junyan He <junyan...@linux.intel.com>
---
 backend/src/backend/program.cpp | 206 ++++++++++++++++++++++++++++------------
 1 file changed, 147 insertions(+), 59 deletions(-)

diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp
index fc9b03c..6c1a652 100644
--- a/backend/src/backend/program.cpp
+++ b/backend/src/backend/program.cpp
@@ -30,6 +30,7 @@
 #include "ir/liveness.hpp"
 #include "ir/value.hpp"
 #include "ir/unit.hpp"
+#include "clang/Serialization/ASTReader.h"
 #include "llvm/llvm_to_gen.hpp"
 #include "llvm/Config/config.h"
 #include "llvm/Support/Threading.h"
@@ -464,13 +465,25 @@ namespace gbe {
     GBE_SAFE_DELETE(program);
   }
 
+  extern std::string ocl_stdlib_str;
   BVAR(OCL_OUTPUT_BUILD_LOG, false);
-  static bool buildModuleFromSource(const char* input, const char* output, 
std::string options,
-                                    size_t stringSize, char *err, size_t 
*errSize) {
+
+  static bool createClangInstance(FILE *clFile, const char *input,
+          const char *source, const char* pch_name,
+          std::vector<std::string>& cl_opts, std::vector<std::string>& 
define_opts,
+          clang::CompilerInstance& Clang, std::string& ErrorString,
+          clang::DiagnosticsEngine*& Diags_ptr) {
     // Arguments to pass to the clang frontend
     vector<const char *> args;
     bool bOpt = true;
     bool bFastMath = false;
+    bool pch_valid = false;
+
+    std::string options;
+    for (auto it = std::begin(cl_opts); it != std::end(cl_opts); ++it) {
+      options += *it;
+      options += " ";
+    }
 
     vector<std::string> useless; //hold substrings to avoid c_str free
     size_t start = 0, end = 0;
@@ -478,10 +491,9 @@ namespace gbe {
        clang unsupport options:
        -cl-denorms-are-zero, -cl-strict-aliasing
        -cl-no-signed-zeros, -cl-fp32-correctly-rounded-divide-sqrt
-       all support options, refer to clang/include/clang/Driver/Options.inc
-    */
+       all support options, refer to clang/include/clang/Driver/Options.inc */
     const std::string unsupportedOptions("-cl-denorms-are-zero, 
-cl-strict-aliasing,"
-                                         "-cl-no-signed-zeros, 
-cl-fp32-correctly-rounded-divide-sqrt");
+            "-cl-no-signed-zeros, -cl-fp32-correctly-rounded-divide-sqrt");
     while (end != std::string::npos) {
       end = options.find(' ', start);
       std::string str = options.substr(start, end - start);
@@ -507,11 +519,11 @@ namespace gbe {
     // FIXME as we don't support function call currently, we may encounter
     // build problem with -O0 as we rely on always inline all functions 
option. 
     if(bOpt)
-      args.push_back("-O2");
+        args.push_back("-O2");
     else
-      args.push_back("-O1");
+        args.push_back("-O1");
     if(bFastMath)
-      args.push_back("-D __FAST_RELAXED_MATH__=1");
+        args.push_back("-D __FAST_RELAXED_MATH__=1");
 #if LLVM_VERSION_MINOR <= 2
     args.push_back("-triple");
     args.push_back("nvptx");
@@ -524,7 +536,6 @@ namespace gbe {
     args.push_back(input);
 
     // The compiler invocation needs a DiagnosticsEngine so it can report 
problems
-    std::string ErrorString;
     llvm::raw_string_ostream ErrorInfo(ErrorString);
     llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts = new 
clang::DiagnosticOptions();
     DiagOpts->ShowCarets = false;
@@ -533,26 +544,26 @@ namespace gbe {
     args.push_back("ptx32");
 
     clang::TextDiagnosticPrinter *DiagClient =
-                             new clang::TextDiagnosticPrinter(ErrorInfo, 
*DiagOpts)
-    llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new 
clang::DiagnosticIDs());
-    clang::DiagnosticsEngine Diags(DiagID, DiagClient);
+        new clang::TextDiagnosticPrinter(ErrorInfo, *DiagOpts)
+        llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new 
clang::DiagnosticIDs());
+    clang::DiagnosticsEngine *Diags = new clang::DiagnosticsEngine(DiagID, 
DiagClient);
 #else
     args.push_back("-ffp-contract=off");
 
     clang::TextDiagnosticPrinter *DiagClient =
-                             new clang::TextDiagnosticPrinter(ErrorInfo, 
&*DiagOpts);
+        new clang::TextDiagnosticPrinter(ErrorInfo, &*DiagOpts);
     llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new 
clang::DiagnosticIDs());
-    clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+    clang::DiagnosticsEngine *Diags = new clang::DiagnosticsEngine(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);
+            &args[0],
+            &args[0] + args.size(),
+            *Diags);
+
+    Diags_ptr = Diags;
 
-    // Create the compiler instance
-    clang::CompilerInstance Clang;
     Clang.setInvocation(CI.take());
     // Get ready to report problems
 #if LLVM_VERSION_MINOR <= 2
@@ -569,8 +580,40 @@ namespace gbe {
     clang::LangOptions & lang_opts = Clang.getLangOpts();
     lang_opts.OpenCL = 1;
 
-    clang::PreprocessorOptions prep_opt = Clang.getPreprocessorOpts();
-    prep_opt.DisablePCHValidation = 1;
+    clang::PreprocessorOptions& prep_opt = Clang.getPreprocessorOpts();
+    /* Check the PCH conformance here. */
+    if (pch_name) {
+      Clang.createFileManager();
+      clang::FileManager& FileMgr = Clang.getFileManager();
+      if (clang::ASTReader::isAcceptableASTFile(std::string(pch_name), FileMgr,
+                  Clang.getLangOpts(),
+                  Clang.getTargetOpts(),
+                  Clang.getPreprocessorOpts())) {
+          prep_opt.ImplicitPCHInclude = std::string(pch_name);
+         prep_opt.Includes.push_back(std::string(pch_name));
+          /* Need not to check again. */
+         prep_opt.DisablePCHValidation = 1;
+          pch_valid = true;
+      }
+    }
+
+    if (!pch_valid) {
+      fwrite(ocl_stdlib_str.c_str(), strlen(ocl_stdlib_str.c_str()), 1, 
clFile);
+    }
+
+    // Write the source to the cl file
+    fwrite(source, strlen(source), 1, clFile);
+
+    /* Add back the defines. */
+    for (auto it = std::begin(define_opts); it != std::end(define_opts); ++it) 
{
+       prep_opt.addMacroDef(*it);
+    }
+
+    return true;
+  }
+
+  static bool buildModuleFromSource(clang::CompilerInstance& Clang, 
std::string& ErrorString,
+          const char* output, size_t stringSize, char *err, size_t *errSize) {
 
     //llvm flags need command line parsing to take effect
     if (!Clang.getFrontendOpts().LLVMArgs.empty()) {
@@ -585,6 +628,8 @@ namespace gbe {
       delete [] Args;
     }
 
+    clang::PreprocessorOptions prep_opt = Clang.getPreprocessorOpts();
+
     // Create an action and make the compiler instance carry it out
     llvm::OwningPtr<clang::CodeGenAction> Act(new clang::EmitLLVMOnlyAction());
     auto retVal = Clang.ExecuteAction(*Act);
@@ -630,8 +675,6 @@ namespace gbe {
     return true;
   }
 
-  extern std::string ocl_stdlib_str;
-
   BVAR(OCL_USE_PCH, true);
   static gbe_program programNewFromSource(const char *source,
                                           size_t stringSize,
@@ -639,6 +682,7 @@ namespace gbe {
                                           char *err,
                                           size_t *errSize)
   {
+
     char clStr[L_tmpnam+1], llStr[L_tmpnam+1];
     const std::string clName = std::string(tmpnam_r(clStr)) + ".cl"; /* 
unsafe! */
     const std::string llName = std::string(tmpnam_r(llStr)) + ".ll"; /* 
unsafe! */
@@ -648,16 +692,17 @@ namespace gbe {
     FILE *clFile = fopen(clName.c_str(), "w");
     FATAL_IF(clFile == NULL, "Failed to open temporary file");
 
+    std::string PCH_suffix;
     bool usePCH = true;
     bool findPCH = false;
 
     /* Because our header file is so big, we want to avoid recompile the 
header from
        scratch. We use the PCH support of Clang to save the huge compiling 
time.
-       We just use the most general build opt to build the PCH header file, so 
if
-       user pass new build options here, the PCH can not pass the Clang's 
compitable
-       validating. Clang will do three kinds of compatible check: Language 
Option,
-       Target Option and Preprocessing Option. Other kinds of options such as 
the
-       CodeGen options will not affect the AST result, so no need to check.
+       We just use the most general build opt to build the PCH header file.
+       Beyond veresion check, Clang will do three kinds of compatible check:
+       Language Option, Target Option and Preprocessing Option.
+       Other kinds of options such as the CodeGen options will not affect the 
AST result,
+       so no need to check.
 
        According to OpenCL 1.1's spec, the CL build options:
        -D name=definition
@@ -680,29 +725,68 @@ namespace gbe {
        -w
        Our header should not block the compiling because of warning.
 
-       So we just disable the PCH validation of Clang and do the judgement by 
ourself. */
+       because the -D define will make the conformance check fail, we will 
filter
+       the defines out before check and set it back later.  */
+
+    std::vector<std::string> cl_opts;
+    std::vector<std::string> define_opts;
 
     if(options) {
       char *p;
+      char *tmp_c = new char[strlen(options) + 1];
+      memcpy(tmp_c, options, strlen(options) + 1);
+      p = ::strtok(tmp_c, " ");
+      while (p != NULL)
+      {
+        if (*p == '-' && *(p + 1) == 'D') {
+          if (strlen(p) == 2) {
+            p = strtok(NULL, " ");
+            if (*p == '-') {// wrong parameter?
+              p = strtok(NULL, " ");
+              continue;
+            }
+          } else {
+            p += 2;
+          }
+
+          define_opts.push_back(std::string(p));
+        } else {
+          cl_opts.push_back(std::string(p));
+        }
+
+       p = strtok(NULL, " ");
+      }
+      delete[] tmp_c;
+
       const char * incompatible_opts[] = {
           "-cl-single-precision-constant",
-//        "-cl-denorms-are-zero",
-          "-cl-std=",
+          "-cl-std=CL1.1"
       };
+
+      bool has_suffix = false;
+      for (auto it = std::begin(cl_opts); it != std::end(cl_opts); it++) {
+        for (unsigned int i = 0; i < sizeof(incompatible_opts)/sizeof(char *); 
i++ ) {
+          if (*it == std::string(incompatible_opts[i])) {
+            if (has_suffix == false) {
+              PCH_suffix = incompatible_opts[i];
+              has_suffix = true;
+            } else {
+              usePCH = false;
+              PCH_suffix = "";
+              break;
+            }
+          }
+        }
+
+        if (!usePCH)
+          break;
+      }
+
       const char * incompatible_defs[] = {
           "GET_FLOAT_WORD",
           "__NV_CL_C_VERSION",
           "GEN7_SAMPLER_CLAMP_BORDER_WORKAROUND"
       };
-
-      for (unsigned int i = 0; i < sizeof(incompatible_opts)/sizeof(char *); 
i++ ) {
-        p = strstr(const_cast<char *>(options), incompatible_opts[i]);
-        if (p) {
-          usePCH = false;
-          break;
-        }
-      }
-
       if (usePCH) {
         for (unsigned int i = 0; i < sizeof(incompatible_defs)/sizeof(char *); 
i++ ) {
           p = strstr(const_cast<char *>(options), incompatible_defs[i]);
@@ -712,34 +796,38 @@ namespace gbe {
           }
         }
       }
-
-      clOpt += options;
     }
 
     std::string dirs = PCH_OBJECT_DIR;
     std::istringstream idirs(dirs);
 
-    while (getline(idirs, pchHeaderName, ';')) {
-      if(access(pchHeaderName.c_str(), R_OK) == 0) {
-        findPCH = true;
-        break;
+    if (usePCH) {
+      while (getline(idirs, pchHeaderName, ';')) {
+        if(pchHeaderName.find(PCH_suffix) != std::string::npos &&
+            access(pchHeaderName.c_str(), R_OK) == 0) {
+          findPCH = true;
+          break;
+        }
       }
     }
 
-    if (usePCH && findPCH) {
-      clOpt += " -include-pch ";
-      clOpt += pchHeaderName;
-      clOpt += " ";
-    } else
-      fwrite(ocl_stdlib_str.c_str(), strlen(ocl_stdlib_str.c_str()), 1, 
clFile);
-
-    // Write the source to the cl file
-    fwrite(source, strlen(source), 1, clFile);
+    // Create the compiler instance
+    std::string ErrorString;
+    clang::CompilerInstance Clang;
+    clang::DiagnosticsEngine* Diags;
+    if (!createClangInstance(clFile, clName.c_str(),
+           source, findPCH ? pchHeaderName.c_str() : NULL,
+           cl_opts, define_opts, Clang, ErrorString, Diags)) {
+      remove(llName.c_str());
+      remove(clName.c_str());
+      delete Diags;
+      fclose(clFile);
+      return NULL;
+    }
     fclose(clFile);
 
     gbe_program p;
-    if (buildModuleFromSource(clName.c_str(), llName.c_str(), clOpt.c_str(),
-                              stringSize, err, errSize)) {
+    if (buildModuleFromSource(Clang, ErrorString, llName.c_str(), stringSize, 
err, errSize)) {
     // Now build the program from llvm
       static std::mutex gbe_mutex;
       gbe_mutex.lock();
@@ -750,8 +838,7 @@ namespace gbe {
         err += *errSize;
         clangErrSize = *errSize;
       }
-      p = gbe_program_new_from_llvm(llName.c_str(), stringSize,
-                                    err, errSize);
+      p = gbe_program_new_from_llvm(llName.c_str(), stringSize, err, errSize);
       if (err != NULL)
         *errSize += clangErrSize;
       gbe_mutex.unlock();
@@ -759,6 +846,7 @@ namespace gbe {
     } else
       p = NULL;
     remove(clName.c_str());
+    delete Diags;
     return p;
   }
 
-- 
1.8.3.2

_______________________________________________
Beignet mailing list
Beignet@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/beignet

Reply via email to