CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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) 2016 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
21namespace CppAD {
22namespace cg {
23
29template<class Base>
30class LlvmModelLibraryProcessor : public LlvmBaseModelLibraryProcessor<Base> {
31protected:
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;
37public:
38
45 LlvmBaseModelLibraryProcessor<Base>(librarySourceGen),
46 _version("3.8") {
47 }
48
49 virtual ~LlvmModelLibraryProcessor() = default;
50
54 inline const std::string& getVersion() const {
55 return _version;
56 }
57
61 inline void setIncludePaths(const std::vector<std::string>& includePaths) {
62 _includePaths = includePaths;
63 }
64
68 inline const std::vector<std::string>& getIncludePaths() const {
69 return _includePaths;
70 }
71
76 std::unique_ptr<LlvmModelLibrary<Base>> create() {
77#if 0
78 llvm::sys::Path clangPath = llvm::sys::Program::FindProgramByName("clang");
79 // Arguments to pass to the clang driver:
80 // clang getinmemory.c -lcurl -v
82 args.push_back(clangPath.c_str());
83 args.push_back(inputPath.c_str());
84 args.push_back("-l");
85 args.push_back("curl");
86 args.push_back("-v"); // verbose
87
88 // The clang driver needs a DiagnosticsEngine so it can report problems
89 clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(llvm::errs(), clang::DiagnosticOptions());
90 clang::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(new clang::DiagnosticIDs());
91 clang::DiagnosticsEngine Diags(DiagID, DiagClient);
92
93 // Create the clang driver
94 clang::driver::Driver TheDriver(args[0], llvm::sys::getDefaultTargetTriple(), outputPath, true, Diags);
95#endif
96 // backup output format so that it can be restored
97 OStreamConfigRestore coutb(std::cout);
98
99 _linker.reset(nullptr);
100
101 this->modelLibraryHelper_->startingJob("", JobTimer::JIT_MODEL_LIBRARY);
102
103 llvm::InitializeAllTargetMCs();
104 llvm::InitializeAllTargets();
105 llvm::InitializeAllAsmPrinters();
106
107 _context.reset(new llvm::LLVMContext());
108
109 const std::map<std::string, ModelCSourceGen<Base>*>& models = this->modelLibraryHelper_->getModels();
110 for (const auto& p : models) {
111 const std::map<std::string, std::string>& modelSources = this->getSources(*p.second);
112 createLlvmModules(modelSources);
113 }
114
115 const std::map<std::string, std::string>& sources = this->getLibrarySources();
116 createLlvmModules(sources);
117
118 const std::map<std::string, std::string>& customSource = this->modelLibraryHelper_->getCustomSources();
119 createLlvmModules(customSource);
120
121 llvm::InitializeNativeTarget();
122
123 std::unique_ptr<LlvmModelLibrary<Base>> lib(new LlvmModelLibrary3_8<Base>(std::move(_module), _context));
124
125 this->modelLibraryHelper_->finishedJob();
126
127 return lib;
128 }
129
135 std::unique_ptr<LlvmModelLibrary<Base>> create(ClangCompiler<Base>& clang) {
136 using namespace llvm;
137
138 // backup output format so that it can be restored
139 OStreamConfigRestore coutb(std::cout);
140
141 _linker.release();
142
143 std::unique_ptr<LlvmModelLibrary<Base>> lib;
144
145 this->modelLibraryHelper_->startingJob("", JobTimer::JIT_MODEL_LIBRARY);
146
147 try {
151 const std::set<std::string>& bcFiles = this->createBitCode(clang, "3.8");
152
156 llvm::InitializeAllTargets();
157 llvm::InitializeAllAsmPrinters();
158
159 _context.reset(new llvm::LLVMContext());
160
161 std::unique_ptr<Module> linkerModule;
162
163 for (const std::string& itbc : bcFiles) {
164 // load bitcode file
165
166 ErrorOr<std::unique_ptr<MemoryBuffer>> buffer = MemoryBuffer::getFile(itbc);
167 if (buffer.get() == nullptr) {
168 throw CGException(buffer.getError().message());
169 }
170
171 // create the module
172 ErrorOr<std::unique_ptr<Module>> module = llvm::parseBitcodeFile(buffer.get()->getMemBufferRef(), *_context.get());
173 if(module.get() == nullptr) {
174 throw CGException(module.getError().message());
175 }
176
177 // link modules together
178 if (_linker.get() == nullptr) {
179 linkerModule.reset(module.get().release());
180 _linker.reset(new llvm::Linker(*linkerModule)); // module not destroyed
181 } else {
182 if (_linker->linkInModule(std::move(module.get()))) { // module destroyed
183 throw CGException("Failed to link");
184 }
185 }
186 }
187
188 llvm::InitializeNativeTarget();
189
190 // voila
191 lib.reset(new LlvmModelLibrary3_8<Base>(std::move(linkerModule), _context));
192
193 } catch (...) {
194 clang.cleanup();
195 throw;
196 }
197 clang.cleanup();
198
199 this->modelLibraryHelper_->finishedJob();
200
201 return lib;
202 }
203
204 static inline std::unique_ptr<LlvmModelLibrary<Base>> create(ModelLibraryCSourceGen<Base>& modelLibraryHelper) {
205 LlvmModelLibraryProcessor<Base> p(modelLibraryHelper);
206 return p.create();
207 }
208
209protected:
210
211 virtual void createLlvmModules(const std::map<std::string, std::string>& sources) {
212 for (const auto& p : sources) {
213 createLlvmModule(p.first, p.second);
214 }
215 }
216
217 virtual void createLlvmModule(const std::string& filename,
218 const std::string& source) {
219 using namespace llvm;
220 using namespace clang;
221
222 ArrayRef<StringRef> paths;
223 llvm::sys::findProgramByName("clang", paths);
224
225 static const char* argv [] = {"program", "-Wall", "-x", "c", "string-input"}; // -Wall or -v flag is required to avoid an error inside createInvocationFromCommandLine()
226 static const int argc = sizeof (argv) / sizeof (argv[0]);
227
228 IntrusiveRefCntPtr<DiagnosticOptions> diagOpts = new DiagnosticOptions();
229 TextDiagnosticPrinter* diagClient = new TextDiagnosticPrinter(llvm::errs(), &*diagOpts); // will be owned by diags
230 IntrusiveRefCntPtr<DiagnosticIDs> diagID(new DiagnosticIDs());
231 IntrusiveRefCntPtr<DiagnosticsEngine> diags(new DiagnosticsEngine(diagID, &*diagOpts, diagClient));
232
233 ArrayRef<const char*> args(argv + 1, // skip program name
234 argc - 1);
235 std::unique_ptr<CompilerInvocation> invocation(createInvocationFromCommandLine(args, diags));
236 if (invocation.get() == nullptr)
237 throw CGException("Failed to create compiler invocation");
238 CompilerInvocation::setLangDefaults(*invocation->getLangOpts(), IK_C,
239 LangStandard::lang_unspecified);
240 invocation->getFrontendOpts().DisableFree = false; // make sure we free memory (by default it does not)
241
242 // Create a compiler instance to handle the actual work.
243 CompilerInstance compiler;
244 compiler.setInvocation(invocation.release());
245
246
247 // Create the compilers actual diagnostics engine.
248 compiler.createDiagnostics(); //compiler.createDiagnostics(argc, const_cast<char**> (argv));
249 if (!compiler.hasDiagnostics())
250 throw CGException("No diagnostics");
251
252 // Create memory buffer with source text
253 std::unique_ptr<llvm::MemoryBuffer> buffer = llvm::MemoryBuffer::getMemBufferCopy(source, "SIMPLE_BUFFER");
254 if (buffer.get() == nullptr)
255 throw CGException("Failed to create memory buffer");
256
257 // Remap auxiliary name "string-input" to memory buffer
258 PreprocessorOptions& po = compiler.getInvocation().getPreprocessorOpts();
259 po.addRemappedFile("string-input", buffer.release());
260
261 HeaderSearchOptions& hso = compiler.getInvocation().getHeaderSearchOpts();
262 std::string iClangHeaders = this->findInternalClangCHeaders("3.8", hso.ResourceDir);
263 if(!iClangHeaders.empty()) {
264 hso.AddPath(llvm::StringRef(iClangHeaders), clang::frontend::Angled, false, false);
265 }
266
267 for (size_t s = 0; s < _includePaths.size(); s++)
268 hso.AddPath(llvm::StringRef(_includePaths[s]), clang::frontend::Angled, false, false);
269
270 // Create and execute the frontend to generate an LLVM bitcode module.
271 clang::EmitLLVMOnlyAction action(_context.get());
272 if (!compiler.ExecuteAction(action))
273 throw CGException("Failed to emit LLVM bitcode");
274
275 std::unique_ptr<llvm::Module> module = action.takeModule();
276 if (module.get() == nullptr)
277 throw CGException("No module");
278
279 if (_linker.get() == nullptr) {
280 _module.reset(module.release());
281 _linker.reset(new llvm::Linker(*_module.get()));
282 } else {
283 if (_linker->linkInModule(std::move(module))) {
284 throw CGException("LLVM failed to link module");
285 }
286 }
287
288 // NO delete module;
289 // NO delete invocation;
290 //llvm::llvm_shutdown();
291 }
292
293};
294
295} // END cg namespace
296} // END CppAD namespace
297
298#endif
const std::set< std::string > & createBitCode(ClangCompiler< Base > &clang, const std::string &version)
std::unique_ptr< LlvmModelLibrary< Base > > create(ClangCompiler< Base > &clang)
void setIncludePaths(const std::vector< std::string > &includePaths)
std::unique_ptr< LlvmModelLibrary< Base > > create()
const std::vector< std::string > & getIncludePaths() const
LlvmModelLibraryProcessor(ModelLibraryCSourceGen< Base > &librarySourceGen)