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) 2017 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; // must 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  // backup output format so that it can be restored
69  OStreamConfigRestore coutb(std::cout);
70 
71  _linker.reset(nullptr);
72 
73  this->modelLibraryHelper_->startingJob("", JobTimer::JIT_MODEL_LIBRARY);
74 
75  llvm::InitializeAllTargetMCs();
76  llvm::InitializeAllTargets();
77  llvm::InitializeAllAsmPrinters();
78 
79  _context.reset(new llvm::LLVMContext());
80 
81  const std::map<std::string, ModelCSourceGen<Base>*>& models = this->modelLibraryHelper_->getModels();
82  for (const auto& p : models) {
83  const std::map<std::string, std::string>& modelSources = this->getSources(*p.second);
84  createLlvmModules(modelSources);
85  }
86 
87  const std::map<std::string, std::string>& sources = this->getLibrarySources();
88  createLlvmModules(sources);
89 
90  const std::map<std::string, std::string>& customSource = this->modelLibraryHelper_->getCustomSources();
91  createLlvmModules(customSource);
92 
93  llvm::InitializeNativeTarget();
94 
95  std::unique_ptr<LlvmModelLibrary<Base>> lib(new LlvmModelLibrary4_0<Base>(std::move(_module), _context));
96 
97  this->modelLibraryHelper_->finishedJob();
98 
99  return lib;
100  }
101 
109  std::unique_ptr<LlvmModelLibrary<Base>> create(ClangCompiler<Base>& clang) {
110  using namespace llvm;
111 
112  // backup output format so that it can be restored
113  OStreamConfigRestore coutb(std::cout);
114 
115  _linker.release();
116 
117  std::unique_ptr<LlvmModelLibrary<Base>> lib;
118 
119  this->modelLibraryHelper_->startingJob("", JobTimer::JIT_MODEL_LIBRARY);
120 
121  try {
125  const std::set<std::string>& bcFiles = this->createBitCode(clang, "4.0");
126 
130  llvm::InitializeAllTargets();
131  llvm::InitializeAllAsmPrinters();
132 
133  _context.reset(new llvm::LLVMContext());
134 
135  std::unique_ptr<Module> linkerModule;
136 
137  for (const std::string& itbc : bcFiles) {
138  // load bitcode file
139 
140  ErrorOr<std::unique_ptr<MemoryBuffer>> buffer = MemoryBuffer::getFile(itbc);
141  if (buffer.get() == nullptr) {
142  throw CGException(buffer.getError().message());
143  }
144 
145  // create the module
146  Expected<std::unique_ptr<Module>> moduleOrError = llvm::parseBitcodeFile(buffer.get()->getMemBufferRef(), *_context.get());
147  if (!moduleOrError) {
148  std::ostringstream error;
149  size_t nError = 0;
150  handleAllErrors(moduleOrError.takeError(), [&](ErrorInfoBase& eib) {
151  if (nError > 0) error << "; ";
152  error << eib.message();
153  nError++;
154  });
155  throw CGException(error.str());
156  }
157 
158  // link modules together
159  if (_linker.get() == nullptr) {
160  linkerModule = std::move(moduleOrError.get());
161  _linker.reset(new llvm::Linker(*linkerModule)); // module not destroyed
162  } else {
163  if (_linker->linkInModule(std::move(moduleOrError.get()))) { // module destroyed
164  throw CGException("Failed to link");
165  }
166  }
167  }
168 
169  llvm::InitializeNativeTarget();
170 
171  // voila
172  lib.reset(new LlvmModelLibrary4_0<Base>(std::move(linkerModule), _context));
173 
174  } catch (...) {
175  clang.cleanup();
176  throw;
177  }
178  clang.cleanup();
179 
180  this->modelLibraryHelper_->finishedJob();
181 
182  return lib;
183  }
184 
185  static inline std::unique_ptr<LlvmModelLibrary<Base>> create(ModelLibraryCSourceGen<Base>& modelLibraryHelper) {
186  LlvmModelLibraryProcessor<Base> p(modelLibraryHelper);
187  return p.create();
188  }
189 
190 protected:
191 
192  virtual void createLlvmModules(const std::map<std::string, std::string>& sources) {
193  for (const auto& p : sources) {
194  createLlvmModule(p.first, p.second);
195  }
196  }
197 
198  virtual void createLlvmModule(const std::string& filename,
199  const std::string& source) {
200  using namespace llvm;
201  using namespace clang;
202 
203  ArrayRef<StringRef> paths;
204  llvm::sys::findProgramByName("clang", paths);
205 
206  IntrusiveRefCntPtr<DiagnosticOptions> diagOpts = new DiagnosticOptions();
207  TextDiagnosticPrinter* diagClient = new TextDiagnosticPrinter(llvm::errs(), &*diagOpts); // will be owned by diags
208  IntrusiveRefCntPtr<DiagnosticIDs> diagID(new DiagnosticIDs());
209  IntrusiveRefCntPtr<DiagnosticsEngine> diags(new DiagnosticsEngine(diagID, &*diagOpts, diagClient));
210 
211  ArrayRef<const char*> args {"-Wall", "-x", "c", "string-input"}; // -Wall or -v flag is required to avoid an error inside createInvocationFromCommandLine()
212  std::shared_ptr<CompilerInvocation> invocation(createInvocationFromCommandLine(args, diags));
213  if (invocation.get() == nullptr)
214  throw CGException("Failed to create compiler invocation");
215 
216  //invocation->TargetOpts->Triple = llvm::sys::getDefaultTargetTriple();
217 
218  CompilerInvocation::setLangDefaults(*invocation->getLangOpts(), IK_C,
219  llvm::Triple(invocation->TargetOpts->Triple),
220  invocation->getPreprocessorOpts(),
221  LangStandard::lang_unspecified);
222  invocation->getFrontendOpts().DisableFree = false; // make sure we free memory (by default it does not)
223 
224  // Create a compiler instance to handle the actual work.
225  CompilerInstance compiler;
226  compiler.setInvocation(invocation);
227 
228 
229  // Create the compilers actual diagnostics engine.
230  compiler.createDiagnostics(); //compiler.createDiagnostics(argc, const_cast<char**> (argv));
231  if (!compiler.hasDiagnostics())
232  throw CGException("No diagnostics");
233 
234  // Create memory buffer with source text
235  std::unique_ptr<llvm::MemoryBuffer> buffer = llvm::MemoryBuffer::getMemBufferCopy(source, "SIMPLE_BUFFER");
236  if (buffer.get() == nullptr)
237  throw CGException("Failed to create memory buffer");
238 
239  // Remap auxiliary name "string-input" to memory buffer
240  PreprocessorOptions& po = compiler.getInvocation().getPreprocessorOpts();
241  po.addRemappedFile("string-input", buffer.release());
242 
243  HeaderSearchOptions& hso = compiler.getInvocation().getHeaderSearchOpts();
244  std::string iClangHeaders = this->findInternalClangCHeaders("4.0", hso.ResourceDir);
245  if(!iClangHeaders.empty()) {
246  hso.AddPath(llvm::StringRef(iClangHeaders), clang::frontend::Angled, false, false);
247  }
248 
249  for (size_t s = 0; s < _includePaths.size(); s++)
250  hso.AddPath(llvm::StringRef(_includePaths[s]), clang::frontend::Angled, false, false);
251 
252  // Create and execute the frontend to generate an LLVM bitcode module.
253  clang::EmitLLVMOnlyAction action(_context.get());
254  if (!compiler.ExecuteAction(action))
255  throw CGException("Failed to emit LLVM bitcode");
256 
257  std::unique_ptr<llvm::Module> module = action.takeModule();
258  if (module.get() == nullptr)
259  throw CGException("No module");
260 
261  if (_linker.get() == nullptr) {
262  _module.reset(module.release());
263  _linker.reset(new llvm::Linker(*_module.get()));
264  } else {
265  if (_linker->linkInModule(std::move(module))) {
266  throw CGException("LLVM failed to link module");
267  }
268  }
269 
270  // NO delete module;
271  // NO delete invocation;
272  //llvm::llvm_shutdown();
273  }
274 
275 };
276 
277 } // END cg namespace
278 } // END CppAD namespace
279 
280 #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)