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