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