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