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) 2013 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::unique_ptr<llvm::Linker> _linker;
35  std::unique_ptr<llvm::LLVMContext> _context;
36 public:
37 
43  LlvmBaseModelLibraryProcessor<Base>(modelLibraryHelper),
44  _version("3.2") {
45  }
46 
47  virtual ~LlvmModelLibraryProcessor() = default;
48 
52  inline const std::string& getVersion() const {
53  return _version;
54  }
55 
56  inline void setIncludePaths(const std::vector<std::string>& includePaths) {
57  _includePaths = includePaths;
58  }
59 
60  inline const std::vector<std::string>& getIncludePaths() const {
61  return _includePaths;
62  }
63 
64  std::unique_ptr<LlvmModelLibrary<Base>> create() {
65  // backup output format so that it can be restored
66  OStreamConfigRestore coutb(std::cout);
67 
68  _linker.release();
69 
70  this->modelLibraryHelper_->startingJob("", JobTimer::JIT_MODEL_LIBRARY);
71 
72  llvm::InitializeAllTargets();
73  llvm::InitializeAllAsmPrinters();
74 
75  _context.reset(new llvm::LLVMContext());
76 
77  const std::map<std::string, ModelCSourceGen<Base>*>& models = this->modelLibraryHelper_->getModels();
78  for (const auto& p : models) {
79  const std::map<std::string, std::string>& modelSources = this->getSources(*p.second);
80  createLlvmModules(modelSources);
81  }
82 
83  const std::map<std::string, std::string>& sources = this->getLibrarySources();
84  createLlvmModules(sources);
85 
86  const std::map<std::string, std::string>& customSource = this->modelLibraryHelper_->getCustomSources();
87  createLlvmModules(customSource);
88 
89  llvm::InitializeNativeTarget();
90 
91  std::unique_ptr<LlvmModelLibrary<Base>> lib (new LlvmModelLibrary3_2<Base>(_linker->releaseModule(), _context.release()));
92 
93  this->modelLibraryHelper_->finishedJob();
94 
95  return lib;
96  }
97 
98  static inline std::unique_ptr<LlvmModelLibrary<Base>> create(ModelLibraryCSourceGen<Base>& modelLibraryHelper) {
99  LlvmModelLibraryProcessor<Base> p(modelLibraryHelper);
100  return p.create();
101  }
102 
103 protected:
104 
105  virtual void createLlvmModules(const std::map<std::string, std::string>& sources) {
106  for (const auto& p : sources) {
107  createLlvmModule(p.first, p.second);
108  }
109  }
110 
111  virtual void createLlvmModule(const std::string& filename,
112  const std::string& source) {
113  using namespace llvm;
114  using namespace clang;
115 
116  static const char* argv [] = {"program", "-Wall", "-x", "c", "string-input"};
117  static const int argc = sizeof (argv) / sizeof (argv[0]);
118 
119  IntrusiveRefCntPtr<DiagnosticOptions> diagOpts = new DiagnosticOptions();
120  TextDiagnosticPrinter *diagClient = new TextDiagnosticPrinter(llvm::errs(), &*diagOpts); // will be owned by diags
121  IntrusiveRefCntPtr<DiagnosticIDs> diagID(new DiagnosticIDs());
122  IntrusiveRefCntPtr<DiagnosticsEngine> diags(new DiagnosticsEngine(diagID, &*diagOpts, diagClient));
123 
124  ArrayRef<const char *> args(argv + 1, // skip program name
125  argc - 1);
126  std::unique_ptr<CompilerInvocation> invocation(createInvocationFromCommandLine(args, diags));
127  if (invocation.get() == nullptr)
128  throw CGException("Failed to create compiler invocation");
129  CompilerInvocation::setLangDefaults(*invocation->getLangOpts(), IK_C,
130  LangStandard::lang_unspecified);
131  invocation->getFrontendOpts().DisableFree = false; // make sure we free memory (by default it does not)
132 
133  // Create a compiler instance to handle the actual work.
134  CompilerInstance compiler;
135  compiler.setInvocation(invocation.release());
136 
137  // Create the compilers actual diagnostics engine.
138  compiler.createDiagnostics(argc, const_cast<char**> (argv));
139  if (!compiler.hasDiagnostics())
140  throw CGException("No diagnostics");
141 
142  // Create memory buffer with source text
143  llvm::MemoryBuffer * buffer = llvm::MemoryBuffer::getMemBufferCopy(source, "SIMPLE_BUFFER");
144  if (buffer == nullptr)
145  throw CGException("Failed to create memory buffer");
146 
147  // Remap auxiliary name "string-input" to memory buffer
148  PreprocessorOptions& po = compiler.getInvocation().getPreprocessorOpts();
149  po.addRemappedFile("string-input", buffer);
150 
151  HeaderSearchOptions& hso = compiler.getInvocation().getHeaderSearchOpts();
152  for (size_t s = 0; s < _includePaths.size(); s++)
153  hso.AddPath(llvm::StringRef(_includePaths[s]), clang::frontend::Angled, true, false, false);
154 
155  // Create and execute the frontend to generate an LLVM bitcode module.
156  OwningPtr<CodeGenAction> action(new clang::EmitLLVMOnlyAction(_context.get()));
157  if (!compiler.ExecuteAction(*action))
158  throw CGException("Failed to emit LLVM bitcode");
159 
160  llvm::Module* module = action->takeModule();
161  if (module == nullptr)
162  throw CGException("No module");
163 
164  if (_linker.get() == nullptr) {
165  _linker.reset(new llvm::Linker(std::string("MyLinker"), module));
166  } else {
167  std::string errorMsg;
168  if (_linker->LinkInModule(module, &errorMsg)) {
169  throw CGException(errorMsg);
170  }
171  }
172 
173  // NO delete module;
174  // NO delete invocation;
175  //llvm::llvm_shutdown();
176  }
177 
178  inline llvm::Module* mergeModules(const std::vector<llvm::Module*>& modules) {
179  if (modules.empty())
180  return nullptr;
181 
182  std::string progName("MyLinker");
183  std::unique_ptr<llvm::Linker> ld(new llvm::Linker(progName, modules[0]));
184 
185  for (size_t m = 1; m < modules.size(); m++) {
186  std::string errorMsg;
187  if (ld->LinkInModule(modules[m], &errorMsg)) {
188  throw CGException(errorMsg);
189  }
190  }
191 
192  return ld->releaseModule();
193  }
194 
195 };
196 
197 } // END cg namespace
198 } // END CppAD namespace
199 
200 #endif
LlvmModelLibraryProcessor(ModelLibraryCSourceGen< Base > &modelLibraryHelper)