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