OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UdfCompiler.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "UdfCompiler.h"
18 
19 #include <clang/AST/AST.h>
20 #include <clang/AST/ASTConsumer.h>
21 #include <clang/AST/RecursiveASTVisitor.h>
22 #include <clang/Basic/DiagnosticDriver.h>
23 #include <clang/Driver/Compilation.h>
24 #include <clang/Driver/Driver.h>
25 #include <clang/Frontend/CompilerInstance.h>
26 #include <clang/Frontend/FrontendActions.h>
27 #include <clang/Frontend/TextDiagnosticPrinter.h>
28 #include <clang/Parse/ParseAST.h>
29 #include <clang/Tooling/CommonOptionsParser.h>
30 #include <clang/Tooling/Tooling.h>
31 #include <llvm/Support/Program.h>
32 #include <llvm/Support/raw_ostream.h>
33 #include <boost/process/search_path.hpp>
34 #include <cctype>
35 #include <iterator>
36 #include <locale>
37 #include "clang/Basic/Version.h"
38 
39 #if LLVM_VERSION_MAJOR >= 11
40 #include <llvm/Support/Host.h>
41 #endif
42 
43 #include "Logger/Logger.h"
44 #include "OSDependent/heavyai_fs.h"
45 
46 using namespace clang;
47 using namespace clang::tooling;
48 
49 static llvm::cl::OptionCategory ToolingSampleCategory("UDF Tooling");
50 
51 namespace {
52 
53 // By implementing RecursiveASTVisitor, we can specify which AST nodes
54 // we're interested in by overriding relevant methods.
55 
56 class FunctionDeclVisitor : public RecursiveASTVisitor<FunctionDeclVisitor> {
57  public:
58  FunctionDeclVisitor(llvm::raw_fd_ostream& ast_file,
59  SourceManager& s_manager,
60  ASTContext& context)
61  : ast_file_(ast_file), source_manager_(s_manager), context_(context) {
62  source_manager_.getDiagnostics().setShowColors(false);
63  }
64 
65  bool VisitFunctionDecl(FunctionDecl* f) {
66  // Only function definitions (with bodies), not declarations.
67  if (f->hasBody()) {
68  if (getMainFileName() == getFuncDeclFileName(f)) {
69  auto printing_policy = context_.getPrintingPolicy();
70  printing_policy.FullyQualifiedName = 1;
71  printing_policy.UseVoidForZeroParams = 1;
72  printing_policy.PolishForDeclaration = 1;
73  printing_policy.TerseOutput = 1;
74  f->print(ast_file_, printing_policy);
75  ast_file_ << "\n";
76  }
77  }
78 
79  return true;
80  }
81 
82  private:
83  std::string getMainFileName() const {
84  auto f_entry = source_manager_.getFileEntryForID(source_manager_.getMainFileID());
85  return f_entry->getName().str();
86  }
87 
88  std::string getFuncDeclFileName(FunctionDecl* f) const {
89  SourceLocation spell_loc = source_manager_.getSpellingLoc(f->getLocation());
90  PresumedLoc p_loc = source_manager_.getPresumedLoc(spell_loc);
91 
92  return std::string(p_loc.getFilename());
93  }
94 
95  private:
96  llvm::raw_fd_ostream& ast_file_;
97  SourceManager& source_manager_;
98  ASTContext& context_;
99 };
100 
101 // Implementation of the ASTConsumer interface for reading an AST produced
102 // by the Clang parser.
103 class DeclASTConsumer : public ASTConsumer {
104  public:
105  DeclASTConsumer(llvm::raw_fd_ostream& ast_file,
106  SourceManager& s_manager,
107  ASTContext& context)
108  : visitor_(ast_file, s_manager, context) {}
109 
110  // Override the method that gets called for each parsed top-level
111  // declaration.
112  bool HandleTopLevelDecl(DeclGroupRef decl_reference) override {
113  for (DeclGroupRef::iterator b = decl_reference.begin(), e = decl_reference.end();
114  b != e;
115  ++b) {
116  // Traverse the declaration using our AST visitor.
117  visitor_.TraverseDecl(*b);
118  }
119  return true;
120  }
121 
122  private:
124 };
125 
126 // For each source file provided to the tool, a new FrontendAction is created.
127 class HandleDeclAction : public ASTFrontendAction {
128  public:
129  HandleDeclAction(llvm::raw_fd_ostream& ast_file) : ast_file_(ast_file) {}
130 
131  ~HandleDeclAction() override {}
132 
133  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance& instance,
134  StringRef file) override {
135  return std::make_unique<DeclASTConsumer>(
136  ast_file_, instance.getSourceManager(), instance.getASTContext());
137  }
138 
139  private:
140  llvm::raw_fd_ostream& ast_file_;
141 };
142 
143 class ToolFactory : public FrontendActionFactory {
144  public:
145 #if LLVM_VERSION_MAJOR >= 10
146  using FrontendActionPtr = std::unique_ptr<clang::FrontendAction>;
147 #define CREATE_FRONTEND_ACTION(ast_file_) std::make_unique<HandleDeclAction>(ast_file_)
148 #else
149  using FrontendActionPtr = clang::FrontendAction*;
150 #define CREATE_FRONTEND_ACTION(ast_file_) new HandleDeclAction(ast_file_)
151 #endif
152 
153  ToolFactory(llvm::raw_fd_ostream& ast_file) : ast_file_(ast_file) {}
154 
156  return CREATE_FRONTEND_ACTION(ast_file_);
157  }
158 
159  private:
160  llvm::raw_fd_ostream& ast_file_;
161 };
162 
163 const char* convert(const std::string& s) {
164  return s.c_str();
165 }
166 
167 std::string exec_output(std::string cmd) {
168  std::array<char, 128> buffer;
169  std::string result;
170  std::unique_ptr<FILE, decltype(&heavyai::pclose)> pipe(heavyai::popen(cmd.c_str(), "r"),
172  if (!pipe) {
173  throw std::runtime_error("heavyai::popen(\"" + cmd + "\") failed!");
174  }
175  while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
176  result += buffer.data();
177  }
178  return result;
179 }
180 
181 std::tuple<int, int, int> get_clang_version(const std::string& clang_path) {
182  std::string cmd = clang_path + " --version";
183  std::string result = exec_output(cmd);
184  if (result.empty()) {
185  throw std::runtime_error(
186  "Invalid clang binary path detected, cannot find clang binary. Is clang "
187  "installed?");
188  }
189  int major, minor, patchlevel;
190  auto count = sscanf(result.substr(result.find("clang version")).c_str(),
191  "clang version %d.%d.%d",
192  &major,
193  &minor,
194  &patchlevel);
195  if (count != 3) {
196  throw std::runtime_error("Failed to get clang version from output:\n" + result +
197  "\n");
198  }
199  return {major, minor, patchlevel};
200 }
201 
203  public:
204  clang::driver::Driver* getClangDriver() { return &the_driver; }
205  std::tuple<int, int, int> getClangVersion() const { return clang_version; }
206 
207  static UdfClangDriver init(const std::string& clang_path);
208 
209  UdfClangDriver(const UdfClangDriver&) = delete; // no copy
210 
211  protected:
212  UdfClangDriver(const std::string& clang_path,
213  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diag_options);
214 
215  private:
216  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diag_options;
217  clang::DiagnosticConsumer* diag_client;
218  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diag_id;
219  clang::DiagnosticsEngine diags;
220  std::unique_ptr<clang::DiagnosticConsumer> diag_client_owner;
221  clang::driver::Driver the_driver;
222  std::tuple<int, int, int> clang_version;
223 };
224 
225 UdfClangDriver UdfClangDriver::init(const std::string& clang_path) {
226  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diag_options =
227  new DiagnosticOptions();
228  if (!diag_options) {
229  throw std::runtime_error(
230  "Failed to initialize UDF compiler diagnostic options. Aborting UDF compiler "
231  "initialization. Is clang/clang++ installed?");
232  }
233  return UdfClangDriver(clang_path, std::move(diag_options));
234 }
235 
236 UdfClangDriver::UdfClangDriver(
237  const std::string& clang_path,
238  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diag_options)
239  : diag_options(diag_options)
240  , diag_client(new TextDiagnosticPrinter(llvm::errs(), diag_options.get()))
241  , diag_id(new clang::DiagnosticIDs())
242  , diags(diag_id, diag_options.get(), diag_client)
243  , diag_client_owner(diags.takeClient())
244  , the_driver(clang_path.c_str(), llvm::sys::getDefaultTargetTriple(), diags)
245  , clang_version(get_clang_version(clang_path)) {
246  the_driver.CCPrintOptions = 0;
247 
248  if (!boost::filesystem::exists(the_driver.ResourceDir)) {
249  LOG(WARNING) << "clang driver ResourceDir=" << the_driver.ResourceDir
250  << " does not exist";
251  }
252 
253  // Replace clang driver resource directory with clang compiler
254  // resource directory
255  std::string clang_resource_dir = exec_output(clang_path + " -print-resource-dir");
256 
257  // trim clang_resource_dir string from right
258  clang_resource_dir.erase(
259  std::find_if(clang_resource_dir.rbegin(),
260  clang_resource_dir.rend(),
261  [](unsigned char ch) { return !std::isspace(ch); })
262  .base(),
263  clang_resource_dir.end());
264 
265  if (clang_resource_dir != the_driver.ResourceDir) {
266  LOG(WARNING) << "Resetting clang driver ResourceDir to " << clang_resource_dir
267  << " (was " << the_driver.ResourceDir << ")";
268  the_driver.ResourceDir = clang_resource_dir;
269  }
270 
271  // QE-720
272 #if LLVM_VERSION_MAJOR >= 10
273  diags.setSeverity(
274 #if LLVM_VERSION_MAJOR >= 14
275  clang::diag::warn_drv_new_cuda_version,
276 #else
277  clang::diag::warn_drv_unknown_cuda_version,
278 #endif
279  clang::diag::Severity::Ignored,
280  clang::SourceLocation());
281 #endif
282 
283  // Ignore `error: cannot find libdevice for sm_75` as irrelevant for
284  // astparser as well as for LLVM IR generation
285  diags.setSeverity(clang::diag::err_drv_no_cuda_libdevice,
286  clang::diag::Severity::Ignored,
287  clang::SourceLocation());
288 }
289 
290 std::string get_clang_path(const std::string& clang_path_override) {
291  if (clang_path_override.empty()) {
292  const auto clang_path = (llvm::sys::findProgramByName("clang++").get());
293  if (clang_path.empty()) {
294  throw std::runtime_error(
295  "Unable to find clang++ to compile user defined functions");
296  }
297  return clang_path;
298  } else {
299  if (!boost::filesystem::exists(clang_path_override)) {
300  throw std::runtime_error("Path provided for udf compiler " + clang_path_override +
301  " does not exist.");
302  }
303 
304  if (boost::filesystem::is_directory(clang_path_override)) {
305  throw std::runtime_error("Path provided for udf compiler " + clang_path_override +
306  " is not to the clang++ executable.");
307  }
308  }
309  return clang_path_override;
310 }
311 
312 } // namespace
313 
315  const std::string& clang_path_override)
316  : clang_path_(get_clang_path(clang_path_override))
317 #ifdef HAVE_CUDA
318  , target_arch_(target_arch)
319 #endif
320 {
321  // To ifguard unsupported code included in heavydbTypes.h (i.e. <shared_mutex>)
322  clang_options_.emplace_back(std::string("-D UDF_COMPILED"));
323 }
324 
326  const std::string& clang_path_override,
327  const std::vector<std::string> clang_options)
328  : clang_path_(get_clang_path(clang_path_override))
329  , clang_options_(clang_options)
330 #ifdef HAVE_CUDA
331  , target_arch_(target_arch)
332 #endif
333 {
334  // To ifguard unsupported code included in heavydbTypes.h (i.e. <shared_mutex>)
335  clang_options_.emplace_back(std::string("-D UDF_COMPILED"));
336 }
337 
338 std::pair<std::string, std::string> UdfCompiler::compileUdf(
339  const std::string& udf_file_name) const {
340  LOG(INFO) << "UDFCompiler filename to compile: " << udf_file_name;
341  if (!boost::filesystem::exists(udf_file_name)) {
342  throw std::runtime_error("User defined function file " + udf_file_name +
343  " does not exist.");
344  }
345 
346  // create the AST file for the input function
347  generateAST(udf_file_name);
348 
349  // Compile udf file to generate cpu and gpu bytecode files
350  std::string cpu_file_name = "";
351  std::string cuda_file_name = "";
352 
353  cpu_file_name = compileToLLVMIR(udf_file_name);
354 
355 #ifdef HAVE_CUDA
356  try {
357  cuda_file_name = compileToNVVMIR(udf_file_name);
358  } catch (const std::exception& e) {
359  LOG(WARNING)
360  << "Failed to generate GPU IR for UDF " + udf_file_name +
361  ", attempting to use CPU compiled IR for GPU.\nUDF Compiler exception: " +
362  e.what();
363  }
364 #endif
365  return std::make_pair(cpu_file_name, cuda_file_name);
366 }
367 
368 namespace {
369 
370 std::string remove_file_extension(const std::string& path) {
371  if (path == "." || path == "..") {
372  return path;
373  }
374 
375  size_t pos = path.find_last_of("\\/.");
376  if (pos != std::string::npos && path[pos] == '.') {
377  return path.substr(0, pos);
378  }
379 
380  return path;
381 }
382 
383 std::string get_file_ext(const std::string& s) {
384  size_t i = s.rfind('.', s.length());
385  if (1 != std::string::npos) {
386  return (s.substr(i + 1, s.length() - i));
387  }
388 }
389 
390 void replace_extension(std::string& s, const std::string& new_ext) {
391  std::string::size_type i = s.rfind('.', s.length());
392 
393  if (i != std::string::npos) {
394  s.replace(i + 1, get_file_ext(s).length(), new_ext);
395  }
396 }
397 
398 } // namespace
399 
400 std::string UdfCompiler::genNVVMIRFilename(const std::string& udf_file_name) {
401  return remove_file_extension(udf_file_name) + "_gpu.bc";
402 }
403 
404 std::string UdfCompiler::genLLVMIRFilename(const std::string& udf_file_name) {
405  return remove_file_extension(udf_file_name) + "_cpu.bc";
406 }
407 
409  const std::vector<std::string>& command_line) const {
410  UdfClangDriver compiler_driver = UdfClangDriver::init(clang_path_);
411  auto the_driver(compiler_driver.getClangDriver());
412 
413  std::vector<const char*> clang_command_opts;
414  clang_command_opts.reserve(command_line.size() + clang_options_.size());
415  // add required options first
416  std::transform(std::begin(command_line),
417  std::end(command_line),
418  std::back_inserter(clang_command_opts),
419  [&](const std::string& str) { return str.c_str(); });
420 
421  // If there were additional clang options passed to the system, append them here
422  if (!clang_options_.empty()) {
423  std::transform(std::begin(clang_options_),
424  std::end(clang_options_),
425  std::back_inserter(clang_command_opts),
426  [&](const std::string& str) { return str.c_str(); });
427  }
428 
429  std::unique_ptr<driver::Compilation> compilation(
430  the_driver->BuildCompilation(clang_command_opts));
431  if (!compilation) {
432  throw std::runtime_error("failed to build compilation object!");
433  }
434  auto [clang_version_major, clang_version_minor, clang_version_patchlevel] =
435  compiler_driver.getClangVersion();
436  if (clang_version_major != CLANG_VERSION_MAJOR
437  // mismatch of clang driver and compulier versions requires
438  // modified workflow that removes incompatible driver flags for
439  // compiler.
440  || CLANG_VERSION_MAJOR == 9
441  // clang driver 9 requires cudatoolkit 8 that we don't support,
442  // hence switching to modified clang compiler 9 workflow that is
443  // able to produce bytecode to GPU when using cudatoolkit 11.
444  ) {
445  /* Fix incompatibilities when driver and clang versions differ.
446  */
447  auto& jobs = compilation->getJobs();
448  CHECK_EQ(jobs.size(), size_t(1));
449  auto& job = *jobs.begin();
450 
451  std::string cmd = job.getExecutable();
452  int skip = 0;
453  std::string last = "";
454 
455  for (auto& arg : job.getArguments()) {
456  const std::string& s = arg;
457  if (skip > 0) {
458  skip--;
459  last = s;
460  continue;
461  }
462 
463  // inclusion of __clang_cuda_runtime_wrapper.h leads to either
464  // clang >9 compilation failure or clang 9 failure for using
465  // cuda >8 (unsupported CUDA version).
466  if (s == "-include") {
467  last = s;
468  continue;
469  }
470  if (last == "-include") {
471  if (s != "__clang_cuda_runtime_wrapper.h") {
472  cmd += " -include " + s;
473  }
474  last = s;
475  continue;
476  }
477 
478  // Using -ffcuda-is-device flag produces empty gpu module
479  if (s == "-fcuda-is-device") {
480  last = s;
481  continue;
482  }
483 
484  if constexpr (CLANG_VERSION_MAJOR == 9) {
485  if (clang_version_major > 9) {
486  // The following clang 9 flags are unknown to clang >9:
487  if (s == "-masm-verbose" || s == "-fuse-init-array" ||
488  s == "-dwarf-column-info" || s == "-momit-leaf-frame-pointer" ||
489  s == "-fdiagnostics-show-option" || s == "-mdisable-fp-elim") {
490  last = s;
491  continue;
492  }
493  if (s == "-fmessage-length") {
494  skip = 1;
495  last = s;
496  continue;
497  }
498  }
499  }
500 
501  if constexpr (CLANG_VERSION_MAJOR == 10) {
502  if (clang_version_major > 10) {
503  // The following clang 10 flags are unknown to clang >10:
504  if (s == "-masm-verbose" || s == "-dwarf-column-info" ||
505  s == "-fdiagnostics-show-option") {
506  last = s;
507  continue;
508  }
509  if (s == "-fmessage-length") {
510  skip = 1;
511  last = s;
512  continue;
513  }
514  }
515  }
516 
517  if constexpr (CLANG_VERSION_MAJOR >= 10) {
518  if (clang_version_major < 10) {
519  // The following clang >10 flags are unknown to clang <10:
520  if (s == "-fno-rounding-math" || s.rfind("-mframe-pointer=", 0) == 0 ||
521  s.rfind("-fgnuc-version=", 0) == 0) {
522  last = s;
523  continue;
524  }
525  }
526  }
527 
528  if constexpr (CLANG_VERSION_MAJOR == 11) {
529  if (clang_version_major < 11) {
530  // The following clang 11 flags are unknown to clang <11:
531  if (s == "-fno-verbose-asm") {
532  last = s;
533  continue;
534  }
535  if (s == "-aux-target-cpu") {
536  last = s;
537  skip = 1;
538  continue;
539  }
540  }
541  }
542 
543  cmd += " " + s;
544  last = s;
545  }
546  // TODO: Here we don't use the_driver->ExecuteCompilation because
547  // could not find a better way to modify driver arguments. As a
548  // workaround, we run clang compiler via pipe (it could be run
549  // also via shell).
550  exec_output(cmd);
551  return 0;
552  }
553 
554  llvm::SmallVector<std::pair<int, const driver::Command*>, 10> failing_commands;
555  int res = the_driver->ExecuteCompilation(*compilation, failing_commands);
556  if (res < 0) {
557  for (const std::pair<int, const driver::Command*>& p : failing_commands) {
558  if (p.first) {
559  the_driver->generateCompilationDiagnostics(*compilation, *p.second);
560  }
561  }
562  }
563  return res;
564 }
565 
566 #ifdef HAVE_CUDA
567 std::string UdfCompiler::compileToNVVMIR(const std::string& udf_file_name) const {
568  const auto gpu_out_filename = genNVVMIRFilename(udf_file_name);
569 
570  std::vector<std::string> command_line{clang_path_,
571  "-c",
572  "-O2",
573  "-emit-llvm",
574  "-o",
575  gpu_out_filename,
576  "-std=c++17",
577  "-DNO_BOOST"};
578 
579  command_line.emplace_back("--cuda-gpu-arch=" +
581  command_line.emplace_back("--cuda-device-only");
582  command_line.emplace_back("-xcuda");
583  command_line.emplace_back("--no-cuda-version-check");
584  const auto cuda_path = get_cuda_home();
585  if (cuda_path != "") {
586  command_line.emplace_back("--cuda-path=" + cuda_path);
587  }
588 
589  command_line.emplace_back(udf_file_name);
590 
591  // clean up from previous runs
592  boost::filesystem::remove(gpu_out_filename);
593  auto status = compileFromCommandLine(command_line);
594  // make sure that compilation actually succeeded by checking the
595  // output file:
596  if (!status && !boost::filesystem::exists(gpu_out_filename)) {
597  throw std::runtime_error(
598  "Failed to generate GPU UDF IR in CUDA mode with error code " +
599  std::to_string(status));
600  }
601  return gpu_out_filename;
602 }
603 #endif
604 
605 std::string UdfCompiler::compileToLLVMIR(const std::string& udf_file_name) const {
606  std::string cpu_out_filename = genLLVMIRFilename(udf_file_name);
607 
608  std::vector<std::string> command_line{clang_path_,
609  "-c",
610  "-O2",
611  "-emit-llvm",
612  "-o",
613  cpu_out_filename,
614  "-std=c++17",
615  "-DNO_BOOST",
616  udf_file_name};
617  auto res = compileFromCommandLine(command_line);
618  if (res != 0) {
619  throw std::runtime_error("Failed to compile CPU UDF (status code " +
620  std::to_string(res) + ")");
621  }
622  if (!boost::filesystem::exists(cpu_out_filename)) {
623  throw std::runtime_error("udf compile did not produce output file " +
624  cpu_out_filename);
625  }
626  return cpu_out_filename;
627 }
628 
629 void UdfCompiler::generateAST(const std::string& file_name) const {
630  UdfClangDriver the_driver = UdfClangDriver::init(clang_path_);
631  std::string resource_path = the_driver.getClangDriver()->ResourceDir;
632  std::string include_option =
633  std::string("-I") + resource_path + std::string("/include");
634 
635  std::vector<std::string> arg_vector;
636  arg_vector.emplace_back("astparser");
637  arg_vector.emplace_back(file_name);
638  arg_vector.emplace_back("--");
639  arg_vector.emplace_back("-DNO_BOOST");
640  arg_vector.emplace_back(include_option);
641  arg_vector.emplace_back("-std=c++17");
642 
643  if (clang_options_.size() > 0) {
644  std::copy(
645  clang_options_.begin(), clang_options_.end(), std::back_inserter(arg_vector));
646  }
647  std::vector<const char*> arg_vec2;
649  arg_vector.begin(), arg_vector.end(), std::back_inserter(arg_vec2), convert);
650 
651  int num_args = arg_vec2.size();
652 #if LLVM_VERSION_MAJOR > 12
653  auto op = CommonOptionsParser::create(num_args, &arg_vec2[0], ToolingSampleCategory);
654  ClangTool tool(op->getCompilations(), op->getSourcePathList());
655 #else
656  CommonOptionsParser op(num_args, &arg_vec2[0], ToolingSampleCategory);
657  ClangTool tool(op.getCompilations(), op.getSourcePathList());
658 #endif
659 
660  std::string out_name(file_name);
661  std::string file_ext("ast");
662  replace_extension(out_name, file_ext);
663 
664  std::error_code out_error_info;
665  llvm::raw_fd_ostream out_file(
666  llvm::StringRef(out_name), out_error_info, llvm::sys::fs::OF_None);
667 
668  auto factory = std::make_unique<ToolFactory>(out_file);
669  const auto result = tool.run(factory.get());
670  if (result != 0) {
671  throw std::runtime_error(
672  "Unable to create AST file for udf compilation (error code " +
673  std::to_string(result) + ")");
674  }
675 }
676 
677 std::string UdfCompiler::getAstFileName(const std::string& udf_file_name) {
678  auto ast_file_name = udf_file_name;
679  replace_extension(ast_file_name, "ast");
680  return ast_file_name;
681 }
std::unique_ptr< clang::DiagnosticConsumer > diag_client_owner
#define CHECK_EQ(x, y)
Definition: Logger.h:301
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &instance, StringRef file) override
std::vector< std::string > clang_options_
Definition: UdfCompiler.h:73
std::string getFuncDeclFileName(FunctionDecl *f) const
Definition: UdfCompiler.cpp:88
static std::string getAstFileName(const std::string &udf_file_name)
#define LOG(tag)
Definition: Logger.h:285
llvm::IntrusiveRefCntPtr< clang::DiagnosticIDs > diag_id
int compileFromCommandLine(const std::vector< std::string > &command_line) const
std::string get_clang_path(const std::string &clang_path_override)
bool HandleTopLevelDecl(DeclGroupRef decl_reference) override
std::string exec_output(std::string cmd)
int32_t pclose(::FILE *fh)
Definition: heavyai_fs.cpp:82
FunctionDeclVisitor(llvm::raw_fd_ostream &ast_file, SourceManager &s_manager, ASTContext &context)
Definition: UdfCompiler.cpp:58
std::pair< FILE *, std::string > create(const std::string &basePath, const int fileId, const size_t pageSize, const size_t numPages)
Definition: File.cpp:55
std::tuple< int, int, int > get_clang_version(const std::string &clang_path)
std::string to_string(char const *&&v)
::FILE * popen(const char *command, const char *type)
Definition: heavyai_fs.cpp:78
std::string get_cuda_home(void)
Definition: CudaMgr.cpp:583
void generateAST(const std::string &file_name) const
void init(LogOptions const &log_opts)
Definition: Logger.cpp:364
DEVICE auto copy(ARGS &&...args)
Definition: gpu_enabled.h:51
std::string remove_file_extension(const std::string &path)
OUTPUT transform(INPUT const &input, FUNC const &func)
Definition: misc.h:320
ToolFactory(llvm::raw_fd_ostream &ast_file)
static std::string deviceArchToSM(const NvidiaDeviceArch arch)
Definition: CudaMgr.h:162
void replace_extension(std::string &s, const std::string &new_ext)
llvm::IntrusiveRefCntPtr< clang::DiagnosticOptions > diag_options
UdfCompiler(CudaMgr_Namespace::NvidiaDeviceArch target_arch, const std::string &clang_path_override="")
static std::string genNVVMIRFilename(const std::string &udf_file_name)
#define CREATE_FRONTEND_ACTION(ast_file_)
std::string compileToLLVMIR(const std::string &udf_file_name) const
static std::string genLLVMIRFilename(const std::string &udf_file_name)
std::string get_file_ext(const std::string &s)
torch::Tensor f(torch::Tensor x, torch::Tensor W_target, torch::Tensor b_target)
def error_code
Definition: report.py:244
std::pair< std::string, std::string > compileUdf(const std::string &udf_file_name) const
const char * convert(const std::string &s)
std::string clang_path_
Definition: UdfCompiler.h:72
std::tuple< int, int, int > getClangVersion() const
static llvm::cl::OptionCategory ToolingSampleCategory("UDF Tooling")
DeclASTConsumer(llvm::raw_fd_ostream &ast_file, SourceManager &s_manager, ASTContext &context)