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