CppADCodeGen  2.3.0
A C++ Algorithmic Differentiation Package with Source Code Generation
llvm_model_library_processor.hpp
1 #ifndef CPPAD_CG_LLVM_MODEL_LIBRARY_PROCESSOR_INCLUDED
2 #define CPPAD_CG_LLVM_MODEL_LIBRARY_PROCESSOR_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2016 Ciengis
6  *
7  * CppADCodeGen is distributed under multiple licenses:
8  *
9  * - Eclipse Public License Version 1.0 (EPL1), and
10  * - GNU General Public License Version 3 (GPL3).
11  *
12  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
13  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
14  * ----------------------------------------------------------------------------
15  * Author: Joao Leal
16  */
17 
18 #include <cppad/cg/model/llvm/llvm_base_model_library_processor.hpp>
19 
20 namespace CppAD {
21 namespace cg {
22 
28 template<class Base>
29 class LlvmModelLibraryProcessor : public LlvmBaseModelLibraryProcessor<Base> {
30 protected:
31  std::vector<std::string> _includePaths;
32  std::shared_ptr<llvm::LLVMContext> _context; // should be deleted after _linker and _module (it must come first)
33  std::unique_ptr<llvm::Linker> _linker;
34  std::unique_ptr<llvm::Module> _module;
35 public:
36 
43  LlvmBaseModelLibraryProcessor<Base>(librarySourceGen) {
44  }
45 
46  virtual ~LlvmModelLibraryProcessor() {
47  }
48 
52  inline void setIncludePaths(const std::vector<std::string>& includePaths) {
53  _includePaths = includePaths;
54  }
55 
59  inline const std::vector<std::string>& getIncludePaths() const {
60  return _includePaths;
61  }
62 
67  std::unique_ptr<LlvmModelLibrary<Base>> create() {
68 #if 0
69  llvm::sys::Path clangPath = llvm::sys::Program::FindProgramByName("clang");
70  // Arguments to pass to the clang driver:
71  // clang getinmemory.c -lcurl -v
73  args.push_back(clangPath.c_str());
74  args.push_back(inputPath.c_str());
75  args.push_back("-l");
76  args.push_back("curl");
77  args.push_back("-v"); // verbose
78 
79  // The clang driver needs a DiagnosticsEngine so it can report problems
80  clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(llvm::errs(), clang::DiagnosticOptions());
81  clang::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new clang::DiagnosticIDs());
82  clang::DiagnosticsEngine Diags(DiagID, DiagClient);
83 
84  // Create the clang driver
85  clang::driver::Driver TheDriver(args[0], llvm::sys::getDefaultTargetTriple(), outputPath, true, Diags);
86 #endif
87  // backup output format so that it can be restored
88  OStreamConfigRestore coutb(std::cout);
89 
90  _linker.reset(nullptr);
91 
92  this->modelLibraryHelper_->startingJob("", JobTimer::JIT_MODEL_LIBRARY);
93 
94  llvm::InitializeAllTargetMCs();
95  llvm::InitializeAllTargets();
96  llvm::InitializeAllAsmPrinters();
97 
98  _context.reset(new llvm::LLVMContext());
99 
100  const std::map<std::string, ModelCSourceGen<Base>*>& models = this->modelLibraryHelper_->getModels();
101  for (const auto& p : models) {
102  const std::map<std::string, std::string>& modelSources = this->getSources(*p.second);
103  createLlvmModules(modelSources);
104  }
105 
106  const std::map<std::string, std::string>& sources = this->getLibrarySources();
107  createLlvmModules(sources);
108 
109  const std::map<std::string, std::string>& customSource = this->modelLibraryHelper_->getCustomSources();
110  createLlvmModules(customSource);
111 
112  llvm::InitializeNativeTarget();
113 
114  std::unique_ptr<LlvmModelLibrary<Base>> lib(new LlvmModelLibrary3_8<Base>(std::move(_module), _context));
115 
116  this->modelLibraryHelper_->finishedJob();
117 
118  return lib;
119  }
120 
126  std::unique_ptr<LlvmModelLibrary<Base>> create(ClangCompiler<Base>& clang) {
127  using namespace llvm;
128 
129  // backup output format so that it can be restored
130  OStreamConfigRestore coutb(std::cout);
131 
132  _linker.release();
133 
134  std::unique_ptr<LlvmModelLibrary<Base>> lib;
135 
136  this->modelLibraryHelper_->startingJob("", JobTimer::JIT_MODEL_LIBRARY);
137 
138  try {
142  const std::set<std::string>& bcFiles = this->createBitCode(clang, "3.8");
143 
147  llvm::InitializeAllTargets();
148  llvm::InitializeAllAsmPrinters();
149 
150  _context.reset(new llvm::LLVMContext());
151 
152  std::unique_ptr<Module> linkerModule;
153 
154  for (const std::string& itbc : bcFiles) {
155  // load bitcode file
156 
157  ErrorOr<std::unique_ptr<MemoryBuffer>> buffer = MemoryBuffer::getFile(itbc);
158  if (buffer.get() == nullptr) {
159  throw CGException(buffer.getError().message());
160  }
161 
162  // create the module
163  ErrorOr<std::unique_ptr<Module>> module = llvm::parseBitcodeFile(buffer.get()->getMemBufferRef(), *_context.get());
164  if(module.get() == nullptr) {
165  throw CGException(module.getError().message());
166  }
167 
168  // link modules together
169  if (_linker.get() == nullptr) {
170  linkerModule.reset(module.get().release());
171  _linker.reset(new llvm::Linker(*linkerModule)); // module not destroyed
172  } else {
173  if (_linker->linkInModule(std::move(module.get()))) { // module destroyed
174  throw CGException("Failed to link");
175  }
176  }
177  }
178 
179  llvm::InitializeNativeTarget();
180 
181  // voila
182  lib.reset(new LlvmModelLibrary3_8<Base>(std::move(linkerModule), _context));
183 
184  } catch (...) {
185  clang.cleanup();
186  throw;
187  }
188  clang.cleanup();
189 
190  this->modelLibraryHelper_->finishedJob();
191 
192  return lib;
193  }
194 
195  static inline std::unique_ptr<LlvmModelLibrary<Base>> create(ModelLibraryCSourceGen<Base>& modelLibraryHelper) {
196  LlvmModelLibraryProcessor<Base> p(modelLibraryHelper);
197  return p.create();
198  }
199 
200 protected:
201 
202  virtual void createLlvmModules(const std::map<std::string, std::string>& sources) {
203  for (const auto& p : sources) {
204  createLlvmModule(p.first, p.second);
205  }
206  }
207 
208  virtual void createLlvmModule(const std::string& filename,
209  const std::string& source) {
210  using namespace llvm;
211  using namespace clang;
212 
213  ArrayRef<StringRef> paths;
214  llvm::sys::findProgramByName("clang", paths);
215 
216  static const char* argv [] = {"program", "-Wall", "-x", "c", "string-input"}; // -Wall or -v flag is required to avoid an error inside createInvocationFromCommandLine()
217  static const int argc = sizeof (argv) / sizeof (argv[0]);
218 
219  IntrusiveRefCntPtr<DiagnosticOptions> diagOpts = new DiagnosticOptions();
220  TextDiagnosticPrinter* diagClient = new TextDiagnosticPrinter(llvm::errs(), &*diagOpts); // will be owned by diags
221  IntrusiveRefCntPtr<DiagnosticIDs> diagID(new DiagnosticIDs());
222  IntrusiveRefCntPtr<DiagnosticsEngine> diags(new DiagnosticsEngine(diagID, &*diagOpts, diagClient));
223 
224  ArrayRef<const char*> args(argv + 1, // skip program name
225  argc - 1);
226  std::unique_ptr<CompilerInvocation> invocation(createInvocationFromCommandLine(args, diags));
227  if (invocation.get() == nullptr)
228  throw CGException("Failed to create compiler invocation");
229  CompilerInvocation::setLangDefaults(*invocation->getLangOpts(), IK_C,
230  LangStandard::lang_unspecified);
231  invocation->getFrontendOpts().DisableFree = false; // make sure we free memory (by default it does not)
232 
233  // Create a compiler instance to handle the actual work.
234  CompilerInstance compiler;
235  compiler.setInvocation(invocation.release());
236 
237 
238  // Create the compilers actual diagnostics engine.
239  compiler.createDiagnostics(); //compiler.createDiagnostics(argc, const_cast<char**> (argv));
240  if (!compiler.hasDiagnostics())
241  throw CGException("No diagnostics");
242 
243  // Create memory buffer with source text
244  std::unique_ptr<llvm::MemoryBuffer> buffer = llvm::MemoryBuffer::getMemBufferCopy(source, "SIMPLE_BUFFER");
245  if (buffer.get() == nullptr)
246  throw CGException("Failed to create memory buffer");
247 
248  // Remap auxiliary name "string-input" to memory buffer
249  PreprocessorOptions& po = compiler.getInvocation().getPreprocessorOpts();
250  po.addRemappedFile("string-input", buffer.release());
251 
252  HeaderSearchOptions& hso = compiler.getInvocation().getHeaderSearchOpts();
253  std::string iClangHeaders = this->findInternalClangCHeaders("3.8", hso.ResourceDir);
254  if(!iClangHeaders.empty()) {
255  hso.AddPath(llvm::StringRef(iClangHeaders), clang::frontend::Angled, false, false);
256  }
257 
258  for (size_t s = 0; s < _includePaths.size(); s++)
259  hso.AddPath(llvm::StringRef(_includePaths[s]), clang::frontend::Angled, false, false);
260 
261  // Create and execute the frontend to generate an LLVM bitcode module.
262  clang::EmitLLVMOnlyAction action(_context.get());
263  if (!compiler.ExecuteAction(action))
264  throw CGException("Failed to emit LLVM bitcode");
265 
266  std::unique_ptr<llvm::Module> module = action.takeModule();
267  if (module.get() == nullptr)
268  throw CGException("No module");
269 
270  if (_linker.get() == nullptr) {
271  _module.reset(module.release());
272  _linker.reset(new llvm::Linker(*_module.get()));
273  } else {
274  if (_linker->linkInModule(std::move(module))) {
275  throw CGException("LLVM failed to link module");
276  }
277  }
278 
279  // NO delete module;
280  // NO delete invocation;
281  //llvm::llvm_shutdown();
282  }
283 
284 };
285 
286 } // END cg namespace
287 } // END CppAD namespace
288 
289 #endif
std::unique_ptr< LlvmModelLibrary< Base > > create()
std::unique_ptr< LlvmModelLibrary< Base > > create(ClangCompiler< Base > &clang)
const std::vector< std::string > & getIncludePaths() const
const std::set< std::string > & createBitCode(ClangCompiler< Base > &clang, const std::string &version)
void setIncludePaths(const std::vector< std::string > &includePaths)
LlvmModelLibraryProcessor(ModelLibraryCSourceGen< Base > &librarySourceGen)