Improvements for Pull Request #240

- little changes at comments and code style
- try to use const in IncrementalCUDADeviceCompiler, where is possible
- move CUDA device code compiler instance to IncrementalParser
- change the members of CuArgs to const and adjust the setCuArgs method
- use std::vector<string> instead llvm::Smallvector<const char *> to build argv for executeAndWait
- improve the error messages of generatePCH(), generatePTX() and generateFatbinary()
- replace m_Counter with a copy in IncrementalCUDADeviceCompiler to avoid involuntary changes
This commit is contained in:
Simeon Ehrig 2018-05-29 16:53:24 +02:00 committed by sftnight
parent 309cebff41
commit 9a4418b3c0
9 changed files with 277 additions and 232 deletions

View File

@ -60,4 +60,4 @@ D: Main developer of cling.
N: Simeon Ehrig N: Simeon Ehrig
E: s.ehrig@hzdr.de E: s.ehrig@hzdr.de
D: CUDA runtime API support D: cling CUDA runtime support

View File

@ -70,7 +70,6 @@ namespace cling {
class LookupHelper; class LookupHelper;
class Value; class Value;
class Transaction; class Transaction;
class IncrementalCUDADeviceCompiler;
///\brief Class that implements the interpreter-like behavior. It manages the ///\brief Class that implements the interpreter-like behavior. It manages the
/// incremental compilation. /// incremental compilation.
@ -159,10 +158,6 @@ namespace cling {
/// ///
std::unique_ptr<LookupHelper> m_LookupHelper; std::unique_ptr<LookupHelper> m_LookupHelper;
///\brief Cling's worker class implementing the compilation of CUDA device code
///
std::unique_ptr<IncrementalCUDADeviceCompiler> m_CUDACompiler;
///\brief Cache of compiled destructors wrappers. ///\brief Cache of compiled destructors wrappers.
std::unordered_map<const clang::RecordDecl*, void*> m_DtorWrappers; std::unordered_map<const clang::RecordDecl*, void*> m_DtorWrappers;
@ -348,8 +343,6 @@ namespace cling {
LookupHelper& getLookupHelper() const { return *m_LookupHelper; } LookupHelper& getLookupHelper() const { return *m_LookupHelper; }
IncrementalCUDADeviceCompiler& getCUDADeviceCompiler() { return *m_CUDACompiler; }
const clang::Parser& getParser() const; const clang::Parser& getParser() const;
clang::Parser& getParser(); clang::Parser& getParser();

View File

@ -1,6 +1,6 @@
//--------------------------------------------------------------------*- C++ -*- //--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :) // CLING - the C++ LLVM-based InterpreterG :)
// author: Simeon Ehrig <simeonehrig@web.de> // author: Simeon Ehrig <s.ehrig@hzdr.de>
// //
// This file is dual-licensed: you can choose to license it under the University // This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See // of Illinois Open Source License or the GNU Lesser General Public License. See
@ -27,70 +27,87 @@
#include <string> #include <string>
// The clang nvptx jit has an growing AST-Tree. At runtime, continuously new
// statements will append to the AST. To improve the compiletime, the existing
// AST will save as PCH-file. The new statements will append via source code
// files. A bug in clang avoids, that more than 4 statements can append to the
// PCH. If the flag is true, it improves the compiletime but it crash after the
// fifth iteration. https://bugs.llvm.org/show_bug.cgi?id=37167
#define PCHMODE 0 #define PCHMODE 0
namespace cling { namespace cling {
IncrementalCUDADeviceCompiler::IncrementalCUDADeviceCompiler( IncrementalCUDADeviceCompiler::IncrementalCUDADeviceCompiler(
std::string filePath, const std::string & filePath,
int optLevel, const int optLevel,
cling::InvocationOptions & invocationOptions, const cling::InvocationOptions & invocationOptions,
clang::CompilerInstance * CI) const clang::CompilerInstance & CI)
: m_Counter(0), : m_FilePath(filePath),
m_FilePath(filePath){ m_FatbinFilePath(CI.getCodeGenOpts().CudaGpuBinaryFileNames.empty()
if(CI->getCodeGenOpts().CudaGpuBinaryFileNames.empty()){ ? "" : CI.getCodeGenOpts().CudaGpuBinaryFileNames[0]),
m_DummyCUPath(m_FilePath + "dummy.cu"),
m_PTXFilePath(m_FilePath + "cling.ptx"),
m_GenericFileName(m_FilePath + "cling") {
if(m_FatbinFilePath.empty()){
llvm::errs() << "Error: CudaGpuBinaryFileNames can't be empty\n"; llvm::errs() << "Error: CudaGpuBinaryFileNames can't be empty\n";
m_Init = false; return;
} else {
m_FatbinFilePath = CI->getCodeGenOpts().CudaGpuBinaryFileNames[0];
m_Init = true;
} }
m_Init = m_Init && generateHelperFiles(); if (!generateHelperFiles())
m_Init = m_Init && searchCompilingTools(invocationOptions); return;
setCuArgs(CI->getLangOpts(), invocationOptions, optLevel, if (!findToolchain(invocationOptions))
CI->getCodeGenOpts().getDebugInfo()); return;
setCuArgs(CI.getLangOpts(), invocationOptions, optLevel,
CI.getCodeGenOpts().getDebugInfo());
m_HeaderSearchOptions = CI->getHeaderSearchOptsPtr(); m_HeaderSearchOptions = CI.getHeaderSearchOptsPtr();
m_Init = true;
} }
void IncrementalCUDADeviceCompiler::setCuArgs( void IncrementalCUDADeviceCompiler::setCuArgs(
clang::LangOptions & langOpts, const clang::LangOptions & langOpts,
cling::InvocationOptions & invocationOptions, const cling::InvocationOptions & invocationOptions,
int & optLevel, clang::codegenoptions::DebugInfoKind debugInfo){ const int intprOptLevel,
const clang::codegenoptions::DebugInfoKind debugInfo){
std::string cppStdVersion;
// Set the c++ standard. Just one condition is possible. // Set the c++ standard. Just one condition is possible.
if(langOpts.CPlusPlus11) if(langOpts.CPlusPlus11)
m_CuArgs.cppStdVersion = "-std=c++11"; cppStdVersion = "-std=c++11";
if(langOpts.CPlusPlus14) if(langOpts.CPlusPlus14)
m_CuArgs.cppStdVersion = "-std=c++14"; cppStdVersion = "-std=c++14";
if(langOpts.CPlusPlus1z) if(langOpts.CPlusPlus1z)
m_CuArgs.cppStdVersion = "-std=c++1z"; cppStdVersion = "-std=c++1z";
if(langOpts.CPlusPlus2a) if(langOpts.CPlusPlus2a)
m_CuArgs.cppStdVersion = "-std=c++2a"; cppStdVersion = "-std=c++2a";
m_CuArgs.optLevel = "-O" + std::to_string(optLevel);
const std::string optLevel = "-O" + std::to_string(intprOptLevel);
std::string ptxSmVersion = "--cuda-gpu-arch=sm_20";
std::string fatbinSmVersion = "--image=profile=compute_20";
if(!invocationOptions.CompilerOpts.CUDAGpuArch.empty()){ if(!invocationOptions.CompilerOpts.CUDAGpuArch.empty()){
m_CuArgs.ptxSmVersion = "--cuda-gpu-arch=" ptxSmVersion = "--cuda-gpu-arch="
+ invocationOptions.CompilerOpts.CUDAGpuArch; + invocationOptions.CompilerOpts.CUDAGpuArch;
m_CuArgs.fatbinSmVersion = "--image=profile=compute_" fatbinSmVersion = "--image=profile=compute_"
+ invocationOptions.CompilerOpts.CUDAGpuArch.substr(3); + invocationOptions.CompilerOpts.CUDAGpuArch.substr(3);
} }
//The generating of the fatbin file is depend of the architecture of the host. //The generating of the fatbin file is depend of the architecture of the host.
llvm::Triple hostTarget(llvm::sys::getDefaultTargetTriple()); llvm::Triple hostTarget(llvm::sys::getDefaultTargetTriple());
m_CuArgs.fatbinArch = hostTarget.isArch64Bit() ? "-64" : "-32"; const std::string fatbinArch = hostTarget.isArch64Bit() ? "-64" : "-32";
m_CuArgs.verbose = invocationOptions.Verbose();
// FIXME : Should not reduce the fine granulated debug options to a simple. // FIXME : Should not reduce the fine granulated debug options to a simple.
// -g // -g
bool debug = false;
if(debugInfo == clang::codegenoptions::DebugLineTablesOnly || if(debugInfo == clang::codegenoptions::DebugLineTablesOnly ||
debugInfo == clang::codegenoptions::LimitedDebugInfo || debugInfo == clang::codegenoptions::LimitedDebugInfo ||
debugInfo == clang::codegenoptions::FullDebugInfo) debugInfo == clang::codegenoptions::FullDebugInfo)
m_CuArgs.debug = true; debug = true;
// FIXME : Cling has problems to detect this arguments. // FIXME : Cling has problems to detect these arguments.
/* /*
if(langOpts.CUDADeviceFlushDenormalsToZero) if(langOpts.CUDADeviceFlushDenormalsToZero)
m_CuArgs.additionalPtxOpt.push_back("-fcuda-flush-denormals-to-zero"); m_CuArgs.additionalPtxOpt.push_back("-fcuda-flush-denormals-to-zero");
@ -99,14 +116,17 @@ namespace cling {
if(langOpts.CUDAAllowVariadicFunctions) if(langOpts.CUDAAllowVariadicFunctions)
m_CuArgs.additionalPtxOpt.push_back("-fcuda-allow-variadic-functions"); m_CuArgs.additionalPtxOpt.push_back("-fcuda-allow-variadic-functions");
*/ */
std::vector<std::string> additionalPtxOpt;
m_CuArgs.fatbinaryOpt = invocationOptions.CompilerOpts.CUDAFatbinaryArgs; m_CuArgs.reset(new IncrementalCUDADeviceCompiler::CUDACompilerArgs(
cppStdVersion, optLevel, ptxSmVersion, fatbinSmVersion, fatbinArch,
invocationOptions.Verbose(), debug, additionalPtxOpt,
invocationOptions.CompilerOpts.CUDAFatbinaryArgs));
} }
bool IncrementalCUDADeviceCompiler::generateHelperFiles(){ bool IncrementalCUDADeviceCompiler::generateHelperFiles(){
// Generate an empty dummy.cu file. // Generate an empty dummy.cu file.
m_DummyCUPath = m_FilePath + "dummy.cu";
std::error_code EC; std::error_code EC;
llvm::raw_fd_ostream dummyCU(m_DummyCUPath, EC, llvm::sys::fs::F_Text); llvm::raw_fd_ostream dummyCU(m_DummyCUPath, EC, llvm::sys::fs::F_Text);
if(EC){ if(EC){
@ -116,13 +136,11 @@ namespace cling {
} }
dummyCU.close(); dummyCU.close();
m_PTXFilePath = m_FilePath + "cling.ptx";
m_GenericFileName = m_FilePath + "cling";
return true; return true;
} }
bool IncrementalCUDADeviceCompiler::searchCompilingTools( bool IncrementalCUDADeviceCompiler::findToolchain(
cling::InvocationOptions & invocationOptions){ const cling::InvocationOptions & invocationOptions){
// Search after clang in the folder of cling. // Search after clang in the folder of cling.
llvm::SmallString<128> cwd; llvm::SmallString<128> cwd;
// get folder of the cling executable to find the clang which is contained // get folder of the cling executable to find the clang which is contained
@ -164,28 +182,35 @@ namespace cling {
return true; return true;
} }
void IncrementalCUDADeviceCompiler::addHeaders( void IncrementalCUDADeviceCompiler::addHeaderSearchPathFlags(
llvm::SmallVectorImpl<std::string> & argv){ llvm::SmallVectorImpl<std::string> & argv){
for(clang::HeaderSearchOptions::Entry e : m_HeaderSearchOptions->UserEntries){ for(clang::HeaderSearchOptions::Entry e : m_HeaderSearchOptions->UserEntries){
if(e.Group == clang::frontend::IncludeDirGroup::Quoted){
argv.push_back("-iquote");
argv.push_back(e.Path);
}
if(e.Group == clang::frontend::IncludeDirGroup::Angled) if(e.Group == clang::frontend::IncludeDirGroup::Angled)
argv.push_back("-I" + e.Path); argv.push_back("-I" + e.Path);
} }
} }
bool IncrementalCUDADeviceCompiler::generateFatbinary(const llvm::StringRef input, bool IncrementalCUDADeviceCompiler::compileDeviceCode(const llvm::StringRef input,
cling::Transaction * T){ const cling::Transaction * const T){
if(!m_Init){ if(!m_Init){
llvm::errs() << "Error: Initializiation of CUDA Device Code Compiler failed\n"; llvm::errs() << "Error: Initializiation of CUDA Device Code Compiler failed\n";
return false; return false;
} }
const unsigned int counter = getCounterCopy();
// Write the (CUDA) C++ source code to a file. // Write the (CUDA) C++ source code to a file.
std::error_code EC; std::error_code EC;
llvm::raw_fd_ostream cuFile(m_GenericFileName + std::to_string(m_Counter) llvm::raw_fd_ostream cuFile(m_GenericFileName + std::to_string(counter)
+ ".cu", EC, llvm::sys::fs::F_Text); + ".cu", EC, llvm::sys::fs::F_Text);
if (EC) { if (EC) {
llvm::errs() << "Could not open " << m_GenericFileName llvm::errs() << "Could not open " << m_GenericFileName
+ std::to_string(m_Counter) << ".cu: " << EC.message() << "\n"; + std::to_string(counter) << ".cu: " << EC.message() << "\n";
return false; return false;
} }
@ -215,23 +240,13 @@ namespace cling {
cuFile.close(); cuFile.close();
if(!generatePCH()){ if(!generatePCH() || !generatePTX() || !generateFatbinary()){
saveFaultyCUfile();
return false;
}
if(!generatePTX()){
saveFaultyCUfile();
return false;
}
if(!generateFatbinaryInternal()){
saveFaultyCUfile(); saveFaultyCUfile();
return false; return false;
} }
#if PCHMODE == 0 #if PCHMODE == 0
llvm::sys::fs::remove(m_GenericFileName + std::to_string(m_Counter) llvm::sys::fs::remove(m_GenericFileName + std::to_string(counter)
+".cu.pch"); +".cu.pch");
#endif #endif
@ -240,72 +255,76 @@ namespace cling {
} }
bool IncrementalCUDADeviceCompiler::generatePCH() { bool IncrementalCUDADeviceCompiler::generatePCH() {
const unsigned int counter = getCounterCopy();
// clang++ -std=c++xx -Ox -S -Xclang -emit-pch ${clingHeaders} cling[0-9].cu // clang++ -std=c++xx -Ox -S -Xclang -emit-pch ${clingHeaders} cling[0-9].cu
// -D__CLING__ -o cling[0-9].cu.pch [-include-pch cling[0-9].cu.pch] // -D__CLING__ -o cling[0-9].cu.pch [-include-pch cling[0-9].cu.pch]
// --cuda-gpu-arch=sm_[1-7][0-9] -pthread --cuda-device-only [-v] [-g] // --cuda-gpu-arch=sm_[1-7][0-9] -pthread --cuda-device-only [-v] [-g]
// ${m_CuArgs.additionalPtxOpt} // ${m_CuArgs->additionalPtxOpt}
llvm::SmallVector<const char*, 256> argv; llvm::SmallVector<std::string, 256> argv;
// First argument have to be the program name. // First argument have to be the program name.
argv.push_back(m_ClangPath.c_str()); argv.push_back(m_ClangPath);
argv.push_back(m_CuArgs.cppStdVersion.c_str()); argv.push_back(m_CuArgs->cppStdVersion);
argv.push_back(m_CuArgs.optLevel.c_str()); argv.push_back(m_CuArgs->optLevel);
argv.push_back("-S"); argv.push_back("-S");
argv.push_back("-Xclang"); argv.push_back("-Xclang");
argv.push_back("-emit-pch"); argv.push_back("-emit-pch");
llvm::SmallVector<std::string, 256> headers; addHeaderSearchPathFlags(argv);
addHeaders(headers);
for(std::string & s : headers)
argv.push_back(s.c_str());
// Is necessary for the cling runtime header. // Is necessary for the cling runtime header.
argv.push_back("-D__CLING__"); argv.push_back("-D__CLING__");
std::string cuFilePath = m_GenericFileName + std::to_string(m_Counter) argv.push_back(m_GenericFileName + std::to_string(counter) + ".cu");
+ ".cu";
argv.push_back(cuFilePath.c_str());
argv.push_back("-o"); argv.push_back("-o");
std::string outputname = m_GenericFileName + std::to_string(m_Counter) argv.push_back(m_GenericFileName + std::to_string(counter) +".cu.pch");
+".cu.pch";
argv.push_back(outputname.c_str());
// If a previos file exist, include it. // If a previos file exist, include it.
#if PCHMODE == 1 #if PCHMODE == 1
std::string previousFile; if(counter){
if(m_Counter){
previousFile = m_GenericFileName + std::to_string(m_Counter-1) +".cu.pch";
argv.push_back("-include-pch"); argv.push_back("-include-pch");
argv.push_back(previousFile.c_str()); argv.push_back(m_GenericFileName + std::to_string(counter-1) +".cu.pch");
} }
#else #else
std::vector<std::string> previousFiles; if(counter){
if(m_Counter){ for(unsigned int i = 0; i <= counter-1; ++i){
for(unsigned int i = 0; i <= m_Counter-1; ++i){
previousFiles.push_back(m_GenericFileName + std::to_string(i) +".cu");
argv.push_back("-include"); argv.push_back("-include");
argv.push_back(previousFiles[i].c_str()); argv.push_back(m_GenericFileName + std::to_string(i) +".cu");
} }
} }
#endif #endif
argv.push_back(m_CuArgs.ptxSmVersion.c_str()); argv.push_back(m_CuArgs->ptxSmVersion);
argv.push_back("-pthread"); argv.push_back("-pthread");
argv.push_back("--cuda-device-only"); argv.push_back("--cuda-device-only");
if(m_CuArgs.verbose) if(m_CuArgs->verbose)
argv.push_back("-v"); argv.push_back("-v");
if(m_CuArgs.debug) if(m_CuArgs->debug)
argv.push_back("-g"); argv.push_back("-g");
for(std::string & s : m_CuArgs.additionalPtxOpt){ for(const std::string & s : m_CuArgs->additionalPtxOpt){
argv.push_back(s.c_str()); argv.push_back(s.c_str());
} }
std::vector<const char *> argvChar;
argvChar.resize(argv.size()+1);
std::transform(argv.begin(), argv.end(), argvChar.begin(),
[&](const std::string & s)
{
return s.c_str();
}
);
// Argv list have to finish with a nullptr. // Argv list have to finish with a nullptr.
argv.push_back(nullptr); argvChar.push_back(nullptr);
std::string executionError; std::string executionError;
int res = llvm::sys::ExecuteAndWait(m_ClangPath.c_str(), argv.data(), int res = llvm::sys::ExecuteAndWait(m_ClangPath.c_str(), argvChar.data(),
nullptr, {}, 0, 0, &executionError); nullptr, {}, 0, 0, &executionError);
if(res){ if(res){
llvm::errs() << "error at launching clang instance to generate PCH file\n" llvm::errs() << "cling::IncrementalCUDADeviceCompiler::generatePCH(): error compiling PCH file:\n"
<< executionError << "\n"; << m_ClangPath;
for(const char * c : argvChar)
llvm::errs() << " " << c;
llvm::errs() << '\n' << executionError << "\n";
return false; return false;
} }
@ -313,80 +332,106 @@ namespace cling {
} }
bool cling::IncrementalCUDADeviceCompiler::generatePTX() { bool cling::IncrementalCUDADeviceCompiler::generatePTX() {
const unsigned int counter = getCounterCopy();
// clang++ -std=c++xx -Ox -S dummy.cu -o cling.ptx -include-pch // clang++ -std=c++xx -Ox -S dummy.cu -o cling.ptx -include-pch
// cling[0-9].cu.pch --cuda-gpu-arch=sm_xx -pthread --cuda-device-only [-v] // cling[0-9].cu.pch --cuda-gpu-arch=sm_xx -pthread --cuda-device-only [-v]
// [-g] ${m_CuArgs.additionalPtxOpt} // [-g] ${m_CuArgs->additionalPtxOpt}
llvm::SmallVector<const char*, 128> argv; llvm::SmallVector<std::string, 128> argv;
// First argument have to be the program name. // First argument have to be the program name.
argv.push_back(m_ClangPath.c_str()); argv.push_back(m_ClangPath);
argv.push_back(m_CuArgs.cppStdVersion.c_str()); argv.push_back(m_CuArgs->cppStdVersion);
argv.push_back(m_CuArgs.optLevel.c_str()); argv.push_back(m_CuArgs->optLevel);
argv.push_back("-S"); argv.push_back("-S");
argv.push_back(m_DummyCUPath.c_str()); argv.push_back(m_DummyCUPath);
argv.push_back("-o"); argv.push_back("-o");
argv.push_back(m_PTXFilePath.c_str()); argv.push_back(m_PTXFilePath);
argv.push_back("-include-pch"); argv.push_back("-include-pch");
std::string pchFile = m_GenericFileName + std::to_string(m_Counter) +".cu.pch"; argv.push_back(m_GenericFileName + std::to_string(counter) +".cu.pch");
argv.push_back(pchFile.c_str()); argv.push_back(m_CuArgs->ptxSmVersion);
argv.push_back(m_CuArgs.ptxSmVersion.c_str());
argv.push_back("-pthread"); argv.push_back("-pthread");
argv.push_back("--cuda-device-only"); argv.push_back("--cuda-device-only");
if(m_CuArgs.verbose) if(m_CuArgs->verbose)
argv.push_back("-v"); argv.push_back("-v");
if(m_CuArgs.debug) if(m_CuArgs->debug)
argv.push_back("-g"); argv.push_back("-g");
for(std::string & s : m_CuArgs.additionalPtxOpt){ for(const std::string & s : m_CuArgs->additionalPtxOpt){
argv.push_back(s.c_str()); argv.push_back(s.c_str());
} }
std::vector<const char *> argvChar;
argvChar.resize(argv.size()+1);
std::transform(argv.begin(), argv.end(), argvChar.begin(),
[&](const std::string & s)
{
return s.c_str();
}
);
// Argv list have to finish with a nullptr. // Argv list have to finish with a nullptr.
argv.push_back(nullptr); argvChar.push_back(nullptr);
std::string executionError; std::string executionError;
int res = llvm::sys::ExecuteAndWait(m_ClangPath.c_str(), argv.data(), int res = llvm::sys::ExecuteAndWait(m_ClangPath.c_str(), argvChar.data(),
nullptr, {}, 0, 0, &executionError); nullptr, {}, 0, 0, &executionError);
if(res){ if(res){
llvm::errs() << "error at launching clang instance to generate ptx code" llvm::errs() << "cling::IncrementalCUDADeviceCompiler::generatePTX(): error compiling PCH file:\n"
<< "\n" << executionError << "\n"; << m_ClangPath;
for(const char * c : argvChar)
llvm::errs() << " " << c;
llvm::errs() << '\n' << executionError << "\n";
return false; return false;
} }
return true; return true;
} }
bool IncrementalCUDADeviceCompiler::generateFatbinaryInternal() { bool IncrementalCUDADeviceCompiler::generateFatbinary() {
// fatbinary --cuda [-32 | -64] --create cling.fatbin // fatbinary --cuda [-32 | -64] --create cling.fatbin
// --image=profile=compute_xx,file=cling.ptx [-g] ${m_CuArgs.fatbinaryOpt} // --image=profile=compute_xx,file=cling.ptx [-g] ${m_CuArgs->fatbinaryOpt}
llvm::SmallVector<const char*, 128> argv; llvm::SmallVector<std::string, 128> argv;
// First argument have to be the program name. // First argument have to be the program name.
argv.push_back(m_FatbinaryPath.c_str()); argv.push_back(m_FatbinaryPath);
argv.push_back("--cuda"); argv.push_back("--cuda");
argv.push_back(m_CuArgs.fatbinArch.c_str()); argv.push_back(m_CuArgs->fatbinArch);
argv.push_back("--create"); argv.push_back("--create");
argv.push_back(m_FatbinFilePath.c_str()); argv.push_back(m_FatbinFilePath);
std::string ptxCode = m_CuArgs.fatbinSmVersion argv.push_back(m_CuArgs->fatbinSmVersion + ",file=" + m_PTXFilePath);
+ ",file=" + m_PTXFilePath; if(m_CuArgs->debug)
argv.push_back(ptxCode.c_str());
if(m_CuArgs.debug)
argv.push_back("-g"); argv.push_back("-g");
for(std::string & s : m_CuArgs.fatbinaryOpt){ for(const std::string & s : m_CuArgs->fatbinaryOpt){
argv.push_back(s.c_str()); argv.push_back(s.c_str());
} }
std::vector<const char *> argvChar;
argvChar.resize(argv.size()+1);
std::transform(argv.begin(), argv.end(), argvChar.begin(),
[&](const std::string & s)
{
return s.c_str();
}
);
// Argv list have to finish with a nullptr. // Argv list have to finish with a nullptr.
argv.push_back(nullptr); argvChar.push_back(nullptr);
std::string executionError; std::string executionError;
int res = llvm::sys::ExecuteAndWait(m_FatbinaryPath.c_str(), argv.data(), int res = llvm::sys::ExecuteAndWait(m_FatbinaryPath.c_str(), argvChar.data(),
nullptr, {}, 0, 0, &executionError); nullptr, {}, 0, 0, &executionError);
if(res){ if(res){
llvm::errs() << "error at launching fatbin" << "\n" << executionError << "\n"; llvm::errs() << "cling::IncrementalCUDADeviceCompiler::generateFatbinary(): error compiling PCH file:\n"
<< m_ClangPath;
for(const char * c : argvChar)
llvm::errs() << " " << c;
llvm::errs() << '\n' << executionError << "\n";
return false; return false;
} }
@ -394,7 +439,7 @@ namespace cling {
} }
void IncrementalCUDADeviceCompiler::dump(){ void IncrementalCUDADeviceCompiler::dump(){
llvm::outs() << "current counter: " << m_Counter << "\n" << llvm::outs() << "current counter: " << getCounterCopy() << "\n" <<
"CUDA device compiler is valid: " << m_Init << "\n" << "CUDA device compiler is valid: " << m_Init << "\n" <<
"file path: " << m_FilePath << "\n" << "file path: " << m_FilePath << "\n" <<
"fatbin file path: " << m_FatbinFilePath << "\n" << "fatbin file path: " << m_FatbinFilePath << "\n" <<
@ -404,35 +449,36 @@ namespace cling {
<< "[0-9]*.cu{.pch}\n" << << "[0-9]*.cu{.pch}\n" <<
"clang++ path: " << m_ClangPath << "\n" << "clang++ path: " << m_ClangPath << "\n" <<
"nvidia fatbinary path: " << m_FatbinaryPath << "\n" << "nvidia fatbinary path: " << m_FatbinaryPath << "\n" <<
"m_CuArgs c++ standard: " << m_CuArgs.cppStdVersion << "\n" << "m_CuArgs c++ standard: " << m_CuArgs->cppStdVersion << "\n" <<
"m_CuArgs opt level: " << m_CuArgs.optLevel << "\n" << "m_CuArgs opt level: " << m_CuArgs->optLevel << "\n" <<
"m_CuArgs SM level for clang nvptx: " "m_CuArgs SM level for clang nvptx: "
<< m_CuArgs.ptxSmVersion << "\n" << << m_CuArgs->ptxSmVersion << "\n" <<
"m_CuArgs SM level for fatbinary: " "m_CuArgs SM level for fatbinary: "
<< m_CuArgs.fatbinSmVersion << "\n" << << m_CuArgs->fatbinSmVersion << "\n" <<
"m_CuArgs fatbinary architectur: " "m_CuArgs fatbinary architectur: "
<< m_CuArgs.fatbinArch << "\n" << << m_CuArgs->fatbinArch << "\n" <<
"m_CuArgs verbose: " << m_CuArgs.verbose << "\n" << "m_CuArgs verbose: " << m_CuArgs->verbose << "\n" <<
"m_CuArgs debug: " << m_CuArgs.debug << "\n"; "m_CuArgs debug: " << m_CuArgs->debug << "\n";
llvm::outs() << "m_CuArgs additional clang nvptx options: "; llvm::outs() << "m_CuArgs additional clang nvptx options: ";
for(std::string & s : m_CuArgs.additionalPtxOpt){ for(const std::string & s : m_CuArgs->additionalPtxOpt){
llvm::outs() << s << " "; llvm::outs() << s << " ";
} }
llvm::outs() << "\n"; llvm::outs() << "\n";
llvm::outs() << "m_CuArgs additional fatbinary options: "; llvm::outs() << "m_CuArgs additional fatbinary options: ";
for(std::string & s : m_CuArgs.fatbinaryOpt){ for(const std::string & s : m_CuArgs->fatbinaryOpt){
llvm::outs() << s << " "; llvm::outs() << s << " ";
} }
llvm::outs() << "\n"; llvm::outs() << "\n";
} }
std::error_code IncrementalCUDADeviceCompiler::saveFaultyCUfile(){ std::error_code IncrementalCUDADeviceCompiler::saveFaultyCUfile(){
const unsigned int counter = getCounterCopy();
unsigned int faultFileCounter = 0; unsigned int faultFileCounter = 0;
// Construct the file path of the current .cu file without extension. // Construct the file path of the current .cu file without extension.
std::string originalCU = m_GenericFileName + std::to_string(m_Counter); std::string originalCU = m_GenericFileName + std::to_string(counter);
// m_Counter will just increased, if the compiling get right. So we need a // counter (= m_Counter) will just increased, if the compiling get right. So we need a
// second counter, if two or more following files fails. // second counter, if two or more following files fails.
std::string faultyCU; std::string faultyCU;
do{ do{
@ -440,8 +486,8 @@ namespace cling {
faultyCU = originalCU + "_fault" + std::to_string(faultFileCounter) + ".cu"; faultyCU = originalCU + "_fault" + std::to_string(faultFileCounter) + ".cu";
} while(llvm::sys::fs::exists(faultyCU)); } while(llvm::sys::fs::exists(faultyCU));
// orginial: cling[m_Counter].cu // orginial: cling[counter].cu
// faulty file: cling[m_Counter]_fault[faultFileCounter].cu // faulty file: cling[counter]_fault[faultFileCounter].cu
return llvm::sys::fs::rename(originalCU + ".cu", faultyCU); return llvm::sys::fs::rename(originalCU + ".cu", faultyCU);
} }

View File

@ -1,6 +1,6 @@
//--------------------------------------------------------------------*- C++ -*- //--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :) // CLING - the C++ LLVM-based InterpreterG :)
// author: Simeon Ehrig <simeonehrig@web.de> // author: Simeon Ehrig <s.ehrig@hzdr.de>
// //
// This file is dual-licensed: you can choose to license it under the University // This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See // of Illinois Open Source License or the GNU Lesser General Public License. See
@ -17,18 +17,18 @@
#include <vector> #include <vector>
namespace cling{ namespace cling{
class InvocationOptions; class InvocationOptions;
class Transaction; class Transaction;
} }
namespace clang { namespace clang {
class CompilerInstance; class CompilerInstance;
class HeaderSearchOptions; class HeaderSearchOptions;
class LangOptions; class LangOptions;
} }
namespace llvm { namespace llvm {
class StringRef; class StringRef;
} }
namespace cling { namespace cling {
@ -39,65 +39,59 @@ namespace cling {
/// ///
class IncrementalCUDADeviceCompiler { class IncrementalCUDADeviceCompiler {
static constexpr unsigned CxxStdCompiledWith() {
// The value of __cplusplus in GCC < 5.0 (e.g. 4.9.3) when
// either -std=c++1y or -std=c++14 is specified is 201300L, which fails
// the test for C++14 or more (201402L) as previously specified.
// I would claim that the check should be relaxed to:
#if __cplusplus > 201402L
return 17;
#elif __cplusplus > 201103L || (defined(LLVM_ON_WIN32) && _MSC_VER >= 1900)
return 14;
#elif __cplusplus >= 201103L
return 11;
#else
#error "Unknown __cplusplus version"
#endif
}
///\brief Contains the arguments for the cling nvptx and the nvidia ///\brief Contains the arguments for the cling nvptx and the nvidia
/// fatbinary tool. The arguments are static and will set at the constructor /// fatbinary tool.
/// of IncrementalCUDADeviceCompiler.
struct CUDACompilerArgs { struct CUDACompilerArgs {
std::string cppStdVersion = "-std=c++" + std::to_string(CxxStdCompiledWith()); const std::string cppStdVersion;
std::string optLevel = "-O0"; const std::string optLevel;
std::string ptxSmVersion = "--cuda-gpu-arch=sm_20"; const std::string ptxSmVersion;
std::string fatbinSmVersion = "--image=profile=compute_20"; const std::string fatbinSmVersion;
///\brief Argument for the fatbinary tool, which is depend, if the OS is ///\brief Argument for the fatbinary tool, which is depend, if the OS is
/// 32 bit or 64 bit. /// 32 bit or 64 bit.
std::string fatbinArch = "-32"; const std::string fatbinArch;
///\brief True, if the flag -v is set. ///\brief True, if the flag -v is set.
bool verbose = false; const bool verbose;
///\brief True, if the flag -g is set. ///\brief True, if the flag -g is set.
bool debug = false; const bool debug;
///\brief A list Arguments, which will passed to the clang nvptx. ///\brief A list Arguments, which will passed to the clang nvptx.
std::vector<std::string> additionalPtxOpt; const std::vector<std::string> additionalPtxOpt;
///\brief A list Arguments, which will passed to the fatbinary tool. ///\brief A list Arguments, which will passed to the fatbinary tool.
std::vector<std::string> fatbinaryOpt; const std::vector<std::string> fatbinaryOpt;
CUDACompilerArgs(std::string cppStdVersion, std::string optLevel,
std::string ptxSmVersion, std::string fatbinSmVersion,
std::string fatbinArch, bool verbose, bool debug,
std::vector<std::string> additionalPtxOpt,
std::vector<std::string> fatbinaryOpt)
: cppStdVersion(cppStdVersion), optLevel(optLevel),
ptxSmVersion(ptxSmVersion), fatbinSmVersion(fatbinSmVersion),
fatbinArch(fatbinArch), verbose(verbose), debug(debug),
additionalPtxOpt(additionalPtxOpt), fatbinaryOpt(fatbinaryOpt) {}
}; };
CUDACompilerArgs m_CuArgs; std::unique_ptr<CUDACompilerArgs> m_CuArgs;
///\brief The counter responsible to generate a chain of .cu source files ///\brief The counter responsible to generate a chain of .cu source files
/// and .cu.pch files. /// and .cu.pch files.
unsigned int m_Counter; unsigned int m_Counter = 0;
///\brief Is true if all necessary files have been generated and clang and ///\brief Is true if all necessary files have been generated and clang and
/// cuda NVIDIA fatbinary are found. /// cuda NVIDIA fatbinary are found.
bool m_Init; bool m_Init = false;
///\brief Path to the folder, where all files will put in. Ordinary the tmp ///\brief Path to the folder, where all files will put in. Ordinary the tmp
/// folder. Have to end with a separator. Can be empty. /// folder. Have to end with a separator. Can be empty.
std::string m_FilePath; const std::string m_FilePath;
///\brief Path to the fatbin file, which will used by the CUDACodeGen. ///\brief Path to the fatbin file, which will used by the CUDACodeGen.
std::string m_FatbinFilePath; const std::string m_FatbinFilePath;
///\brief Path to a empty dummy.cu file. The file is necessary to generate ///\brief Path to a empty dummy.cu file. The file is necessary to generate
/// PTX code from the pch files. /// PTX code from the pch files.
std::string m_DummyCUPath; const std::string m_DummyCUPath;
///\brief Path to the PTX file. Will be reused for every PTX generation. ///\brief Path to the PTX file. Will be reused for every PTX generation.
std::string m_PTXFilePath; const std::string m_PTXFilePath;
///\brief Will be used to generate .cu and .cu.pch files. ///\brief Will be used to generate .cu and .cu.pch files.
std::string m_GenericFileName; const std::string m_GenericFileName;
///\brief Path to the clang++ compiler, which will used to compile the pch ///\brief Path to the clang++ compiler, which will used to compile the pch
/// files and the PTX code. Should be in same folder, as the cling. /// files and the PTX code. Should be in same folder, as the cling.
@ -109,6 +103,11 @@ namespace cling {
/// ///
std::shared_ptr<clang::HeaderSearchOptions> m_HeaderSearchOptions; std::shared_ptr<clang::HeaderSearchOptions> m_HeaderSearchOptions;
///\brief get copy of m_Counter
///
///\returns copy of m_Counter
unsigned int getCounterCopy(){ return m_Counter;}
///\brief Generate the dummy.cu file and set the paths of m_PTXFilePath and ///\brief Generate the dummy.cu file and set the paths of m_PTXFilePath and
/// m_GenericFileName. /// m_GenericFileName.
/// ///
@ -122,12 +121,12 @@ namespace cling {
/// toolkit /// toolkit
/// ///
///\returns True, whether clang and fatbinary was found. ///\returns True, whether clang and fatbinary was found.
bool searchCompilingTools(cling::InvocationOptions & invocationOptions); bool findToolchain(const cling::InvocationOptions & invocationOptions);
///\brief Add the include paths from the interpreter runtime to a argument list. ///\brief Add the include paths from the interpreter runtime to a argument list.
/// ///
///\param [in,out] argv - The include commands will append to the argv vector. ///\param [in,out] argv - The include commands will append to the argv vector.
void addHeaders(llvm::SmallVectorImpl<std::string> & argv); void addHeaderSearchPathFlags(llvm::SmallVectorImpl<std::string> & argv);
///\brief Start an clang compiler with nvptx backend. Read the content of ///\brief Start an clang compiler with nvptx backend. Read the content of
/// cling.cu and compile it to a new PCH file. If predecessor PCH file is /// cling.cu and compile it to a new PCH file. If predecessor PCH file is
@ -147,17 +146,18 @@ namespace cling {
/// m_FatbinFilePath. /// m_FatbinFilePath.
/// ///
///\returns True, if the fatbinary tool returns 0. ///\returns True, if the fatbinary tool returns 0.
bool generateFatbinaryInternal(); bool generateFatbinary();
///\brief The function set the values of m_CuArgs. ///\brief The function set the values of m_CuArgs.
/// ///
///\param [in] langOpts - The LangOptions of the CompilerInstance. ///\param [in] langOpts - The LangOptions of the CompilerInstance.
///\param [in] invocationOptions - The invocationOptions of the interpreter. ///\param [in] invocationOptions - The invocationOptions of the interpreter.
///\param [in] optLevel - The optimization level of the interpreter. ///\param [in] intprOptLevel - The optimization level of the interpreter.
///\param [in] debugInfo - The debugInfo of the CompilerInstance. ///\param [in] debugInfo - The debugInfo of the CompilerInstance.
void setCuArgs(clang::LangOptions & langOpts, void setCuArgs(const clang::LangOptions & langOpts,
cling::InvocationOptions & invocationOptions, int & optLevel, const cling::InvocationOptions & invocationOptions,
clang::codegenoptions::DebugInfoKind debugInfo); const int intprOptLevel,
const clang::codegenoptions::DebugInfoKind debugInfo);
///\brief Save .cu file, if cuda device code compiler failed at translation. ///\brief Save .cu file, if cuda device code compiler failed at translation.
/// ///
@ -176,14 +176,14 @@ namespace cling {
/// clang and the NVIDIA tool fatbinary. /// clang and the NVIDIA tool fatbinary.
///\param [in] CompilerInstance - Will be used for m_CuArgs and the include ///\param [in] CompilerInstance - Will be used for m_CuArgs and the include
/// path handling. /// path handling.
IncrementalCUDADeviceCompiler(std::string filePath, IncrementalCUDADeviceCompiler(const std::string & filePath,
int optLevel, const int optLevel,
cling::InvocationOptions & invocationOptions, const cling::InvocationOptions & invocationOptions,
clang::CompilerInstance * CI); const clang::CompilerInstance & CI);
///\brief Generate an new fatbin file with the path in CudaGpuBinaryFileNames. ///\brief Generate an new fatbin file with the path in CudaGpuBinaryFileNames.
/// It will add the content of input, to the existing source code, which was /// It will add the content of input, to the existing source code, which was
/// passed to generateFatbinary, before. /// passed to compileDeviceCode, before.
/// ///
///\param [in] input - New source code. The function can select, if code ///\param [in] input - New source code. The function can select, if code
/// is relevant for the device side. Have to be valid CUDA C++ code. /// is relevant for the device side. Have to be valid CUDA C++ code.
@ -191,7 +191,8 @@ namespace cling {
/// ///
///\returns True, if all stages of generating fatbin runs right and a new ///\returns True, if all stages of generating fatbin runs right and a new
/// fatbin file is written. /// fatbin file is written.
bool generateFatbinary(const llvm::StringRef input, cling::Transaction * T); bool compileDeviceCode(const llvm::StringRef input,
const cling::Transaction * const T);
///\brief Print some information of the IncrementalCUDADeviceCompiler to ///\brief Print some information of the IncrementalCUDADeviceCompiler to
/// llvm::outs(). For Example the paths of the files and tools. /// llvm::outs(). For Example the paths of the files and tools.

View File

@ -45,6 +45,8 @@
#include "clang/Sema/Sema.h" #include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/SemaDiagnostic.h"
#include "clang/Serialization/ASTWriter.h" #include "clang/Serialization/ASTWriter.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/Support/Path.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
@ -118,7 +120,7 @@ namespace {
m_PrevClient.EndSourceFile(); m_PrevClient.EndSourceFile();
SyncDiagCountWithTarget(); SyncDiagCountWithTarget();
} }
void finish() override { void finish() override {
m_PrevClient.finish(); m_PrevClient.finish();
SyncDiagCountWithTarget(); SyncDiagCountWithTarget();
@ -213,6 +215,34 @@ namespace cling {
m_DiagConsumer.reset(new FilteringDiagConsumer(Diag, false)); m_DiagConsumer.reset(new FilteringDiagConsumer(Diag, false));
initializeVirtualFile(); initializeVirtualFile();
if(m_CI->getFrontendOpts().ProgramAction != frontend::ParseSyntaxOnly &&
m_Interpreter->getOptions().CompilerOpts.CUDA){
// Create temporary folder for all files, which the CUDA device compiler
// will generate.
llvm::SmallString<256> TmpPath;
llvm::StringRef sep = llvm::sys::path::get_separator().data();
llvm::sys::path::system_temp_directory(false, TmpPath);
TmpPath.append(sep.data());
TmpPath.append("cling-%%%%");
TmpPath.append(sep.data());
llvm::SmallString<256> TmpFolder;
llvm::sys::fs::createUniqueFile(TmpPath.c_str(), TmpFolder);
llvm::sys::fs::create_directory(TmpFolder);
// The CUDA fatbin file is the connection beetween the CUDA device
// compiler and the CodeGen of cling. The file will every time reused.
if(getCI()->getCodeGenOpts().CudaGpuBinaryFileNames.empty())
getCI()->getCodeGenOpts().CudaGpuBinaryFileNames.push_back(
std::string(TmpFolder.c_str()) + "cling.fatbin");
m_CUDACompiler.reset(
new IncrementalCUDADeviceCompiler(TmpFolder.c_str(),
m_CI->getCodeGenOpts().OptimizationLevel,
m_Interpreter->getOptions(),
*m_CI));
}
} }
bool bool
@ -794,8 +824,7 @@ namespace cling {
return kSuccessWithWarnings; return kSuccessWithWarnings;
if(!m_Interpreter->isInSyntaxOnlyMode() && m_CI->getLangOpts().CUDA ) if(!m_Interpreter->isInSyntaxOnlyMode() && m_CI->getLangOpts().CUDA )
m_Interpreter->getCUDADeviceCompiler() m_CUDACompiler->compileDeviceCode(input, m_Consumer->getTransaction());
.generateFatbinary(input, m_Consumer->getTransaction());
return kSuccess; return kSuccess;
} }

View File

@ -43,6 +43,7 @@ namespace cling {
class Transaction; class Transaction;
class TransactionPool; class TransactionPool;
class ASTTransformer; class ASTTransformer;
class IncrementalCUDADeviceCompiler;
///\brief Responsible for the incremental parsing and compilation of input. ///\brief Responsible for the incremental parsing and compilation of input.
/// ///
@ -94,6 +95,10 @@ namespace cling {
/// ///
std::unique_ptr<clang::DiagnosticConsumer> m_DiagConsumer; std::unique_ptr<clang::DiagnosticConsumer> m_DiagConsumer;
///\brief Cling's worker class implementing the compilation of CUDA device code
///
std::unique_ptr<IncrementalCUDADeviceCompiler> m_CUDACompiler;
public: public:
enum EParseResult { enum EParseResult {
kSuccess, kSuccess,

View File

@ -20,7 +20,6 @@
#include "ForwardDeclPrinter.h" #include "ForwardDeclPrinter.h"
#include "IncrementalExecutor.h" #include "IncrementalExecutor.h"
#include "IncrementalParser.h" #include "IncrementalParser.h"
#include "IncrementalCUDADeviceCompiler.h"
#include "MultiplexInterpreterCallbacks.h" #include "MultiplexInterpreterCallbacks.h"
#include "TransactionUnloader.h" #include "TransactionUnloader.h"
@ -57,7 +56,6 @@
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Path.h" #include "llvm/Support/Path.h"
#include <string> #include <string>
@ -167,7 +165,7 @@ namespace cling {
m_DyLibManager && m_LookupHelper && m_DyLibManager && m_LookupHelper &&
(isInSyntaxOnlyMode() || m_Executor); (isInSyntaxOnlyMode() || m_Executor);
} }
namespace internal { void symbol_requester(); } namespace internal { void symbol_requester(); }
const char* Interpreter::getVersion() { const char* Interpreter::getVersion() {
@ -238,33 +236,6 @@ namespace cling {
return; return;
} }
if(!isInSyntaxOnlyMode() && m_Opts.CompilerOpts.CUDA){
// Create temporary folder for all files, which the CUDA device compiler
// will generate.
llvm::SmallString<256> TmpPath;
llvm::StringRef sep = llvm::sys::path::get_separator().data();
llvm::sys::path::system_temp_directory(false, TmpPath);
TmpPath.append(sep.data());
TmpPath.append("cling-%%%%");
TmpPath.append(sep.data());
llvm::SmallString<256> TmpFolder;
llvm::sys::fs::createUniqueFile(TmpPath.c_str(), TmpFolder);
llvm::sys::fs::create_directory(TmpFolder);
// The CUDA fatbin file is the connection beetween the CUDA device
// compiler and the CodeGen of cling. The file will every time reused.
if(getCI()->getCodeGenOpts().CudaGpuBinaryFileNames.empty())
getCI()->getCodeGenOpts().CudaGpuBinaryFileNames.push_back(
std::string(TmpFolder.c_str()) + "cling.fatbin");
m_CUDACompiler.reset(
new IncrementalCUDADeviceCompiler(TmpFolder.c_str(),
m_OptLevel,
m_Opts,
getCI()));
}
// Tell the diagnostic client that we are entering file parsing mode. // Tell the diagnostic client that we are entering file parsing mode.
DiagnosticConsumer& DClient = getCI()->getDiagnosticClient(); DiagnosticConsumer& DClient = getCI()->getDiagnosticClient();
DClient.BeginSourceFile(getCI()->getLangOpts(), &PP); DClient.BeginSourceFile(getCI()->getLangOpts(), &PP);
@ -702,7 +673,7 @@ namespace cling {
} }
return Value; return Value;
} }
///\brief Maybe transform the input line to implement cint command line ///\brief Maybe transform the input line to implement cint command line
/// semantics (declarations are global) and compile to produce a module. /// semantics (declarations are global) and compile to produce a module.
/// ///
@ -898,11 +869,11 @@ namespace cling {
// Ignore diagnostics when we tab complete. // Ignore diagnostics when we tab complete.
// This is because we get redefinition errors due to the import of the decls. // This is because we get redefinition errors due to the import of the decls.
clang::IgnoringDiagConsumer* ignoringDiagConsumer = clang::IgnoringDiagConsumer* ignoringDiagConsumer =
new clang::IgnoringDiagConsumer(); new clang::IgnoringDiagConsumer();
childSemaRef.getDiagnostics().setClient(ignoringDiagConsumer, true); childSemaRef.getDiagnostics().setClient(ignoringDiagConsumer, true);
DiagnosticsEngine& parentDiagnostics = this->getCI()->getSema().getDiagnostics(); DiagnosticsEngine& parentDiagnostics = this->getCI()->getSema().getDiagnostics();
std::unique_ptr<DiagnosticConsumer> ownerDiagConsumer = std::unique_ptr<DiagnosticConsumer> ownerDiagConsumer =
parentDiagnostics.takeClient(); parentDiagnostics.takeClient();
auto clientDiagConsumer = parentDiagnostics.getClient(); auto clientDiagConsumer = parentDiagnostics.getClient();
parentDiagnostics.setClient(ignoringDiagConsumer, /*owns*/ false); parentDiagnostics.setClient(ignoringDiagConsumer, /*owns*/ false);

View File

@ -60,4 +60,4 @@ hostOutput[numberOfThreads-1] == numberOfThreads-1 // expected-note {{use '=' to
expectedSum == cudaSum // expected-note {{use '=' to turn this equality comparison into an assignment}} expectedSum == cudaSum // expected-note {{use '=' to turn this equality comparison into an assignment}}
// CHECK: (bool) true // CHECK: (bool) true
.q .q

View File

@ -78,4 +78,4 @@ expectedSum1 == cudaSum1 // expected-note {{use '=' to turn this equality compar
expectedSum2 == cudaSum2 // expected-note {{use '=' to turn this equality comparison into an assignment}} expectedSum2 == cudaSum2 // expected-note {{use '=' to turn this equality comparison into an assignment}}
// CHECK: (bool) true // CHECK: (bool) true
.q .q