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) 2014 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.4") {
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  ClangCompiler<Base> clang;
66  return create(clang);
67  }
68 
69  std::unique_ptr<LlvmModelLibrary<Base>> create(ClangCompiler<Base>& clang) {
70  using namespace llvm;
71 
72  // backup output format so that it can be restored
73  OStreamConfigRestore coutb(std::cout);
74 
75  _linker.release();
76 
77  std::unique_ptr<LlvmModelLibrary<Base>> lib;
78 
79  this->modelLibraryHelper_->startingJob("", JobTimer::JIT_MODEL_LIBRARY);
80 
81  try {
85  const std::set<std::string>& bcFiles = this->createBitCode(clang, "3.4");
86 
90  llvm::InitializeAllTargets();
91  llvm::InitializeAllAsmPrinters();
92 
93  _context.reset(new llvm::LLVMContext());
94 
95  for (const std::string& itbc : bcFiles) {
96  // load bitcode file
97  OwningPtr<MemoryBuffer> buffer;
98 
99  error_code ec = MemoryBuffer::getFile(itbc, buffer);
100  if (buffer.get() == nullptr)
101  throw CGException(ec.message());
102 
103  // create the module
104  std::string errMsg;
105  Module* module = llvm::ParseBitcodeFile(buffer.get(), *_context.get(), &errMsg);
106  if(module == nullptr)
107  throw CGException("Failed to create LLVM bitcode: ", errMsg);
108 
109  // link modules together
110  if (_linker.get() == nullptr) {
111  _linker.reset(new llvm::Linker(module)); // module not destroyed
112  } else {
113  if (_linker->linkInModule(module, &errMsg)) { // module destroyed
114  throw CGException(errMsg);
115  }
116  }
117  }
118 
119  llvm::InitializeNativeTarget();
120 
121  // voila
122  lib.reset(new LlvmModelLibrary3_4<Base>(_linker->getModule(), _context.release()));
123 
124  } catch (...) {
125  clang.cleanup();
126  throw;
127  }
128  clang.cleanup();
129 
130  this->modelLibraryHelper_->finishedJob();
131 
132  return lib;
133  }
134 
135  static inline std::unique_ptr<LlvmModelLibrary<Base>> create(ModelLibraryCSourceGen<Base>& modelLibraryHelper) {
136  LlvmModelLibraryProcessor<Base> p(modelLibraryHelper);
137  return p.create();
138  }
139 
140 protected:
141 #if 0
142 
146  static void createnPrintModule() {
147  using namespace llvm;
148  using namespace clang;
149 
153  std::string source;
154  std::cin >> source;
155 
156  static const char* argv [] = {"program", "-Wall", "-x", "c", "string-input"};
157  static const int argc = sizeof (argv) / sizeof (argv[0]);
158 
159  IntrusiveRefCntPtr<DiagnosticOptions> diagOpts = new DiagnosticOptions();
160  TextDiagnosticPrinter *diagClient = new TextDiagnosticPrinter(llvm::errs(), &*diagOpts); // will be owned by diags
161  IntrusiveRefCntPtr<DiagnosticIDs> diagID(new DiagnosticIDs());
162  IntrusiveRefCntPtr<DiagnosticsEngine> diags(new DiagnosticsEngine(diagID, &*diagOpts, diagClient));
163 
164  ArrayRef<const char *> args(argv + 1, // skip program name
165  argc - 1);
166  std::unique_ptr<CompilerInvocation> invocation(createInvocationFromCommandLine(args, diags));
167  if (invocation.get() == nullptr)
168  throw CGException("Failed to create compiler invocation");
169  CompilerInvocation::setLangDefaults(*invocation->getLangOpts(), IK_C,
170  LangStandard::lang_unspecified);
171  invocation->getFrontendOpts().DisableFree = false; // make sure we free memory (by default it does not)
172 
173  // Create a compiler instance to handle the actual work.
174  CompilerInstance compiler;
175  compiler.setInvocation(invocation.release());
176 
177  // Create the compilers actual diagnostics engine.
178  compiler.createDiagnostics();
179  if (!compiler.hasDiagnostics())
180  throw CGException("No diagnostics");
181 
182  // Create memory buffer with source text
183  llvm::MemoryBuffer * buffer = llvm::MemoryBuffer::getMemBufferCopy(source, "SIMPLE_BUFFER");
184  if (buffer == nullptr)
185  throw CGException("Failed to create memory buffer");
186 
187  // Remap auxiliary name "string-input" to memory buffer
188  PreprocessorOptions& po = compiler.getInvocation().getPreprocessorOpts();
189  po.addRemappedFile("string-input", buffer);
190 
191  HeaderSearchOptions& hso = compiler.getInvocation().getHeaderSearchOpts();
192  for (size_t s = 0; s < _includePaths.size(); s++)
193  hso.AddPath(llvm::StringRef(_includePaths[s]), clang::frontend::Angled, true, false);
194 
195  // Create and execute the frontend to generate an LLVM bitcode module.
196  OwningPtr<CodeGenAction> action(new clang::EmitLLVMOnlyAction(_context.get()));
197 
198  if (!compiler.ExecuteAction(*action))
199  throw CGException("Failed to emit LLVM bitcode");
200 
201  llvm::Module* module = action->takeModule();
202  if (module == nullptr)
203  throw CGException("No module");
204 
208  //std::cout << *module;
209  raw_fd_ostream os(STDOUT_FILENO, true);
210  module->print(os);
211  delete module;
212  }
213 #endif
214 };
215 
216 } // END cg namespace
217 } // END CppAD namespace
218 
219 #endif
std::unique_ptr< LlvmModelLibrary< Base > > create(ClangCompiler< Base > &clang)
const std::set< std::string > & createBitCode(ClangCompiler< Base > &clang, const std::string &version)
LlvmModelLibraryProcessor(ModelLibraryCSourceGen< Base > &modelLibraryHelper)