1 #ifndef CPPAD_CG_LLVM_BASE_MODEL_LIBRARY_PROCESSOR_IMPL_INCLUDED
2 #define CPPAD_CG_LLVM_BASE_MODEL_LIBRARY_PROCESSOR_IMPL_INCLUDED
19 #include <cppad/cg/model/llvm/llvm_base_model_library_processor.hpp>
32 const std::string _version;
33 std::vector<std::string> _includePaths;
34 std::shared_ptr<llvm::LLVMContext> _context;
35 std::unique_ptr<llvm::Linker> _linker;
36 std::unique_ptr<llvm::Module> _module;
45 std::string version) :
47 _version(std::move(version)) {
63 _includePaths = includePaths;
77 std::unique_ptr<LlvmModelLibrary<Base>>
create() {
81 _linker.reset(
nullptr);
83 this->modelLibraryHelper_->startingJob(
"", JobTimer::JIT_MODEL_LIBRARY);
85 llvm::InitializeAllTargetMCs();
86 llvm::InitializeAllTargets();
87 llvm::InitializeAllAsmPrinters();
89 _context.reset(
new llvm::LLVMContext());
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);
97 const std::map<std::string, std::string>& sources = this->getLibrarySources();
98 createLlvmModules(sources);
100 const std::map<std::string, std::string>& customSource = this->modelLibraryHelper_->getCustomSources();
101 createLlvmModules(customSource);
103 llvm::InitializeNativeTarget();
107 this->modelLibraryHelper_->finishedJob();
120 using namespace llvm;
127 std::unique_ptr<LlvmModelLibrary<Base>> lib;
129 this->modelLibraryHelper_->startingJob(
"", JobTimer::JIT_MODEL_LIBRARY);
135 const std::set<std::string>& bcFiles = this->
createBitCode(clang, _version);
140 llvm::InitializeAllTargets();
141 llvm::InitializeAllAsmPrinters();
143 _context.reset(
new llvm::LLVMContext());
145 std::unique_ptr<Module> linkerModule;
147 for (
const std::string& itbc : bcFiles) {
150 ErrorOr<std::unique_ptr<MemoryBuffer>> buffer = MemoryBuffer::getFile(itbc);
151 if (buffer.get() ==
nullptr) {
156 Expected<std::unique_ptr<Module>> moduleOrError = llvm::parseBitcodeFile(buffer.get()->getMemBufferRef(), *_context.get());
157 if (!moduleOrError) {
158 std::ostringstream error;
160 handleAllErrors(moduleOrError.takeError(), [&](ErrorInfoBase& eib) {
161 if (nError > 0) error <<
"; ";
162 error << eib.message();
169 if (_linker.get() ==
nullptr) {
170 linkerModule = std::move(moduleOrError.get());
171 _linker.reset(
new llvm::Linker(*linkerModule));
173 if (_linker->linkInModule(std::move(moduleOrError.get()))) {
179 llvm::InitializeNativeTarget();
190 this->modelLibraryHelper_->finishedJob();
197 virtual void createLlvmModules(
const std::map<std::string, std::string>& sources) {
198 for (
const auto& p : sources) {
199 createLlvmModule(p.first, p.second);
203 virtual void createLlvmModule(
const std::string& filename,
204 const std::string& source) {
205 using namespace llvm;
206 using namespace clang;
208 ArrayRef<StringRef> paths;
209 llvm::sys::findProgramByName(
"clang", paths);
211 IntrusiveRefCntPtr<DiagnosticOptions> diagOpts =
new DiagnosticOptions();
212 auto* diagClient =
new TextDiagnosticPrinter(llvm::errs(), &*diagOpts);
213 IntrusiveRefCntPtr<DiagnosticIDs> diagID(
new DiagnosticIDs());
214 IntrusiveRefCntPtr<DiagnosticsEngine> diags(
new DiagnosticsEngine(diagID, &*diagOpts, diagClient));
216 ArrayRef<const char*> args {
"-Wall",
"-x",
"c",
"string-input"};
217 std::shared_ptr<CompilerInvocation> invocation(createInvocationFromCommandLine(args, diags));
218 if (invocation ==
nullptr)
219 throw CGException(
"Failed to create compiler invocation");
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;
230 CompilerInstance compiler;
231 compiler.setInvocation(invocation);
235 compiler.createDiagnostics();
236 if (!compiler.hasDiagnostics())
237 throw CGException(
"No diagnostics");
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");
245 PreprocessorOptions& po = compiler.getInvocation().getPreprocessorOpts();
246 po.addRemappedFile(
"string-input", buffer.release());
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);
254 for (
size_t s = 0; s < _includePaths.size(); s++)
255 hso.AddPath(llvm::StringRef(_includePaths[s]), clang::frontend::Angled,
false,
false);
258 clang::EmitLLVMOnlyAction action(_context.get());
259 if (!compiler.ExecuteAction(action))
260 throw CGException(
"Failed to emit LLVM bitcode");
262 std::unique_ptr<llvm::Module> module = action.takeModule();
263 if (module ==
nullptr)
264 throw CGException(
"No module");
266 if (_linker.get() ==
nullptr) {
267 _module.reset(module.release());
268 _linker.reset(
new llvm::Linker(*_module.get()));
270 if (_linker->linkInModule(std::move(module))) {
271 throw CGException(
"LLVM failed to link module");