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) 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
21namespace CppAD {
22namespace cg {
23
29template<class Base>
31protected:
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;
36public:
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
103protected:
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)