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