CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
llvm_base_model_library_processor_impl.hpp
1#ifndef CPPAD_CG_LLVM_BASE_MODEL_LIBRARY_PROCESSOR_IMPL_INCLUDED
2#define CPPAD_CG_LLVM_BASE_MODEL_LIBRARY_PROCESSOR_IMPL_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2017 Ciengis
6 * Copyright (C) 2018 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::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 std::string version) :
46 LlvmBaseModelLibraryProcessor<Base>(librarySourceGen),
47 _version(std::move(version)) {
48 }
49
50 virtual ~LlvmBaseModelLibraryProcessorImpl() = default;
51
55 inline const std::string& getVersion() const {
56 return _version;
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 LlvmModelLibraryImpl<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, _version);
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.get() == 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 LlvmModelLibraryImpl<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
195protected:
196
197 virtual void createLlvmModules(const std::map<std::string, std::string>& sources) {
198 for (const auto& p : sources) {
199 createLlvmModule(p.first, p.second);
200 }
201 }
202
203 virtual void createLlvmModule(const std::string& filename,
204 const std::string& source) {
205 using namespace llvm;
206 using namespace clang;
207
208 ArrayRef<StringRef> paths;
209 llvm::sys::findProgramByName("clang", paths);
210
211 IntrusiveRefCntPtr<DiagnosticOptions> diagOpts = new DiagnosticOptions();
212 auto* diagClient = new TextDiagnosticPrinter(llvm::errs(), &*diagOpts); // will be owned by diags
213 IntrusiveRefCntPtr<DiagnosticIDs> diagID(new DiagnosticIDs());
214 IntrusiveRefCntPtr<DiagnosticsEngine> diags(new DiagnosticsEngine(diagID, &*diagOpts, diagClient));
215
216 ArrayRef<const char*> args {"-Wall", "-x", "c", "string-input"}; // -Wall or -v flag is required to avoid an error inside createInvocationFromCommandLine()
217 std::shared_ptr<CompilerInvocation> invocation(createInvocationFromCommandLine(args, diags));
218 if (invocation == nullptr)
219 throw CGException("Failed to create compiler invocation");
220
221 //invocation->TargetOpts->Triple = llvm::sys::getDefaultTargetTriple();
222
223 CompilerInvocation::setLangDefaults(*invocation->getLangOpts(), InputKind::C,
224 llvm::Triple(invocation->TargetOpts->Triple),
225 invocation->getPreprocessorOpts(),
226 LangStandard::lang_unspecified);
227 invocation->getFrontendOpts().DisableFree = false; // make sure we free memory (by default it does not)
228
229 // Create a compiler instance to handle the actual work.
230 CompilerInstance compiler;
231 compiler.setInvocation(invocation);
232
233
234 // Create the compilers actual diagnostics engine.
235 compiler.createDiagnostics(); //compiler.createDiagnostics(argc, const_cast<char**> (argv));
236 if (!compiler.hasDiagnostics())
237 throw CGException("No diagnostics");
238
239 // Create memory buffer with source text
240 std::unique_ptr<llvm::MemoryBuffer> buffer = llvm::MemoryBuffer::getMemBufferCopy(source, "SIMPLE_BUFFER");
241 if (buffer == nullptr)
242 throw CGException("Failed to create memory buffer");
243
244 // Remap auxiliary name "string-input" to memory buffer
245 PreprocessorOptions& po = compiler.getInvocation().getPreprocessorOpts();
246 po.addRemappedFile("string-input", buffer.release());
247
248 HeaderSearchOptions& hso = compiler.getInvocation().getHeaderSearchOpts();
249 std::string iClangHeaders = this->findInternalClangCHeaders(_version, hso.ResourceDir);
250 if(!iClangHeaders.empty()) {
251 hso.AddPath(llvm::StringRef(iClangHeaders), clang::frontend::Angled, false, false);
252 }
253
254 for (size_t s = 0; s < _includePaths.size(); s++)
255 hso.AddPath(llvm::StringRef(_includePaths[s]), clang::frontend::Angled, false, false);
256
257 // Create and execute the frontend to generate an LLVM bitcode module.
258 clang::EmitLLVMOnlyAction action(_context.get());
259 if (!compiler.ExecuteAction(action))
260 throw CGException("Failed to emit LLVM bitcode");
261
262 std::unique_ptr<llvm::Module> module = action.takeModule();
263 if (module == nullptr)
264 throw CGException("No module");
265
266 if (_linker.get() == nullptr) {
267 _module.reset(module.release());
268 _linker.reset(new llvm::Linker(*_module.get()));
269 } else {
270 if (_linker->linkInModule(std::move(module))) {
271 throw CGException("LLVM failed to link module");
272 }
273 }
274
275 // NO delete module;
276 // NO delete invocation;
277 //llvm::llvm_shutdown();
278 }
279
280};
281
282} // END cg namespace
283} // END CppAD namespace
284
285#endif
std::unique_ptr< LlvmModelLibrary< Base > > create(ClangCompiler< Base > &clang)
LlvmBaseModelLibraryProcessorImpl(ModelLibraryCSourceGen< Base > &librarySourceGen, std::string version)
void setIncludePaths(const std::vector< std::string > &includePaths)
const std::set< std::string > & createBitCode(ClangCompiler< Base > &clang, const std::string &version)