1 1.1 joerg //===-- examples/clang-interpreter/main.cpp - Clang C Interpreter Example -===// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg 9 1.1 joerg #include "clang/Basic/DiagnosticOptions.h" 10 1.1 joerg #include "clang/CodeGen/CodeGenAction.h" 11 1.1 joerg #include "clang/Driver/Compilation.h" 12 1.1 joerg #include "clang/Driver/Driver.h" 13 1.1 joerg #include "clang/Driver/Tool.h" 14 1.1 joerg #include "clang/Frontend/CompilerInstance.h" 15 1.1 joerg #include "clang/Frontend/CompilerInvocation.h" 16 1.1 joerg #include "clang/Frontend/FrontendDiagnostic.h" 17 1.1 joerg #include "clang/Frontend/TextDiagnosticPrinter.h" 18 1.1 joerg #include "llvm/ADT/SmallString.h" 19 1.1 joerg #include "llvm/ExecutionEngine/ExecutionEngine.h" 20 1.1 joerg #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 21 1.1 joerg #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 22 1.1 joerg #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" 23 1.1 joerg #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 24 1.1 joerg #include "llvm/ExecutionEngine/SectionMemoryManager.h" 25 1.1 joerg #include "llvm/IR/DataLayout.h" 26 1.1 joerg #include "llvm/IR/Mangler.h" 27 1.1 joerg #include "llvm/IR/Module.h" 28 1.1 joerg #include "llvm/Support/FileSystem.h" 29 1.1 joerg #include "llvm/Support/Host.h" 30 1.1 joerg #include "llvm/Support/ManagedStatic.h" 31 1.1 joerg #include "llvm/Support/Path.h" 32 1.1 joerg #include "llvm/Support/TargetSelect.h" 33 1.1 joerg #include "llvm/Support/raw_ostream.h" 34 1.1 joerg #include "llvm/Target/TargetMachine.h" 35 1.1 joerg 36 1.1 joerg using namespace clang; 37 1.1 joerg using namespace clang::driver; 38 1.1 joerg 39 1.1 joerg // This function isn't referenced outside its translation unit, but it 40 1.1 joerg // can't use the "static" keyword because its address is used for 41 1.1 joerg // GetMainExecutable (since some platforms don't support taking the 42 1.1 joerg // address of main, and some platforms can't implement GetMainExecutable 43 1.1 joerg // without being given the address of a function in the main executable). 44 1.1 joerg std::string GetExecutablePath(const char *Argv0, void *MainAddr) { 45 1.1 joerg return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); 46 1.1 joerg } 47 1.1 joerg 48 1.1 joerg namespace llvm { 49 1.1 joerg namespace orc { 50 1.1 joerg 51 1.1 joerg class SimpleJIT { 52 1.1 joerg private: 53 1.1 joerg ExecutionSession ES; 54 1.1 joerg std::unique_ptr<TargetMachine> TM; 55 1.1 joerg const DataLayout DL; 56 1.1 joerg MangleAndInterner Mangle{ES, DL}; 57 1.1.1.2 joerg JITDylib &MainJD{ES.createBareJITDylib("<main>")}; 58 1.1 joerg RTDyldObjectLinkingLayer ObjectLayer{ES, createMemMgr}; 59 1.1.1.2 joerg IRCompileLayer CompileLayer{ES, ObjectLayer, 60 1.1.1.2 joerg std::make_unique<SimpleCompiler>(*TM)}; 61 1.1 joerg 62 1.1 joerg static std::unique_ptr<SectionMemoryManager> createMemMgr() { 63 1.1 joerg return std::make_unique<SectionMemoryManager>(); 64 1.1 joerg } 65 1.1 joerg 66 1.1 joerg SimpleJIT( 67 1.1 joerg std::unique_ptr<TargetMachine> TM, DataLayout DL, 68 1.1 joerg std::unique_ptr<DynamicLibrarySearchGenerator> ProcessSymbolsGenerator) 69 1.1 joerg : TM(std::move(TM)), DL(std::move(DL)) { 70 1.1 joerg llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); 71 1.1.1.2 joerg MainJD.addGenerator(std::move(ProcessSymbolsGenerator)); 72 1.1 joerg } 73 1.1 joerg 74 1.1 joerg public: 75 1.1.1.2 joerg ~SimpleJIT() { 76 1.1.1.2 joerg if (auto Err = ES.endSession()) 77 1.1.1.2 joerg ES.reportError(std::move(Err)); 78 1.1.1.2 joerg } 79 1.1.1.2 joerg 80 1.1 joerg static Expected<std::unique_ptr<SimpleJIT>> Create() { 81 1.1 joerg auto JTMB = JITTargetMachineBuilder::detectHost(); 82 1.1 joerg if (!JTMB) 83 1.1 joerg return JTMB.takeError(); 84 1.1 joerg 85 1.1 joerg auto TM = JTMB->createTargetMachine(); 86 1.1 joerg if (!TM) 87 1.1 joerg return TM.takeError(); 88 1.1 joerg 89 1.1 joerg auto DL = (*TM)->createDataLayout(); 90 1.1 joerg 91 1.1 joerg auto ProcessSymbolsGenerator = 92 1.1 joerg DynamicLibrarySearchGenerator::GetForCurrentProcess( 93 1.1 joerg DL.getGlobalPrefix()); 94 1.1 joerg 95 1.1 joerg if (!ProcessSymbolsGenerator) 96 1.1 joerg return ProcessSymbolsGenerator.takeError(); 97 1.1 joerg 98 1.1 joerg return std::unique_ptr<SimpleJIT>(new SimpleJIT( 99 1.1 joerg std::move(*TM), std::move(DL), std::move(*ProcessSymbolsGenerator))); 100 1.1 joerg } 101 1.1 joerg 102 1.1 joerg const TargetMachine &getTargetMachine() const { return *TM; } 103 1.1 joerg 104 1.1 joerg Error addModule(ThreadSafeModule M) { 105 1.1.1.2 joerg return CompileLayer.add(MainJD, std::move(M)); 106 1.1 joerg } 107 1.1 joerg 108 1.1 joerg Expected<JITEvaluatedSymbol> findSymbol(const StringRef &Name) { 109 1.1.1.2 joerg return ES.lookup({&MainJD}, Mangle(Name)); 110 1.1 joerg } 111 1.1 joerg 112 1.1 joerg Expected<JITTargetAddress> getSymbolAddress(const StringRef &Name) { 113 1.1 joerg auto Sym = findSymbol(Name); 114 1.1 joerg if (!Sym) 115 1.1 joerg return Sym.takeError(); 116 1.1 joerg return Sym->getAddress(); 117 1.1 joerg } 118 1.1 joerg }; 119 1.1 joerg 120 1.1 joerg } // end namespace orc 121 1.1 joerg } // end namespace llvm 122 1.1 joerg 123 1.1 joerg llvm::ExitOnError ExitOnErr; 124 1.1 joerg 125 1.1 joerg int main(int argc, const char **argv) { 126 1.1 joerg // This just needs to be some symbol in the binary; C++ doesn't 127 1.1 joerg // allow taking the address of ::main however. 128 1.1 joerg void *MainAddr = (void*) (intptr_t) GetExecutablePath; 129 1.1 joerg std::string Path = GetExecutablePath(argv[0], MainAddr); 130 1.1 joerg IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 131 1.1 joerg TextDiagnosticPrinter *DiagClient = 132 1.1 joerg new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); 133 1.1 joerg 134 1.1 joerg IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 135 1.1 joerg DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); 136 1.1 joerg 137 1.1 joerg const std::string TripleStr = llvm::sys::getProcessTriple(); 138 1.1 joerg llvm::Triple T(TripleStr); 139 1.1 joerg 140 1.1 joerg // Use ELF on Windows-32 and MingW for now. 141 1.1 joerg #ifndef CLANG_INTERPRETER_COFF_FORMAT 142 1.1 joerg if (T.isOSBinFormatCOFF()) 143 1.1 joerg T.setObjectFormat(llvm::Triple::ELF); 144 1.1 joerg #endif 145 1.1 joerg 146 1.1 joerg ExitOnErr.setBanner("clang interpreter"); 147 1.1 joerg 148 1.1 joerg Driver TheDriver(Path, T.str(), Diags); 149 1.1 joerg TheDriver.setTitle("clang interpreter"); 150 1.1 joerg TheDriver.setCheckInputsExist(false); 151 1.1 joerg 152 1.1 joerg // FIXME: This is a hack to try to force the driver to do something we can 153 1.1 joerg // recognize. We need to extend the driver library to support this use model 154 1.1 joerg // (basically, exactly one input, and the operation mode is hard wired). 155 1.1 joerg SmallVector<const char *, 16> Args(argv, argv + argc); 156 1.1 joerg Args.push_back("-fsyntax-only"); 157 1.1 joerg std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args)); 158 1.1 joerg if (!C) 159 1.1 joerg return 0; 160 1.1 joerg 161 1.1 joerg // FIXME: This is copied from ASTUnit.cpp; simplify and eliminate. 162 1.1 joerg 163 1.1 joerg // We expect to get back exactly one command job, if we didn't something 164 1.1 joerg // failed. Extract that job from the compilation. 165 1.1 joerg const driver::JobList &Jobs = C->getJobs(); 166 1.1 joerg if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { 167 1.1 joerg SmallString<256> Msg; 168 1.1 joerg llvm::raw_svector_ostream OS(Msg); 169 1.1 joerg Jobs.Print(OS, "; ", true); 170 1.1 joerg Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); 171 1.1 joerg return 1; 172 1.1 joerg } 173 1.1 joerg 174 1.1 joerg const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin()); 175 1.1 joerg if (llvm::StringRef(Cmd.getCreator().getName()) != "clang") { 176 1.1 joerg Diags.Report(diag::err_fe_expected_clang_command); 177 1.1 joerg return 1; 178 1.1 joerg } 179 1.1 joerg 180 1.1 joerg // Initialize a compiler invocation object from the clang (-cc1) arguments. 181 1.1 joerg const llvm::opt::ArgStringList &CCArgs = Cmd.getArguments(); 182 1.1 joerg std::unique_ptr<CompilerInvocation> CI(new CompilerInvocation); 183 1.1 joerg CompilerInvocation::CreateFromArgs(*CI, CCArgs, Diags); 184 1.1 joerg 185 1.1 joerg // Show the invocation, with -v. 186 1.1 joerg if (CI->getHeaderSearchOpts().Verbose) { 187 1.1 joerg llvm::errs() << "clang invocation:\n"; 188 1.1 joerg Jobs.Print(llvm::errs(), "\n", true); 189 1.1 joerg llvm::errs() << "\n"; 190 1.1 joerg } 191 1.1 joerg 192 1.1 joerg // FIXME: This is copied from cc1_main.cpp; simplify and eliminate. 193 1.1 joerg 194 1.1 joerg // Create a compiler instance to handle the actual work. 195 1.1 joerg CompilerInstance Clang; 196 1.1 joerg Clang.setInvocation(std::move(CI)); 197 1.1 joerg 198 1.1 joerg // Create the compilers actual diagnostics engine. 199 1.1 joerg Clang.createDiagnostics(); 200 1.1 joerg if (!Clang.hasDiagnostics()) 201 1.1 joerg return 1; 202 1.1 joerg 203 1.1 joerg // Infer the builtin include path if unspecified. 204 1.1 joerg if (Clang.getHeaderSearchOpts().UseBuiltinIncludes && 205 1.1 joerg Clang.getHeaderSearchOpts().ResourceDir.empty()) 206 1.1 joerg Clang.getHeaderSearchOpts().ResourceDir = 207 1.1 joerg CompilerInvocation::GetResourcesPath(argv[0], MainAddr); 208 1.1 joerg 209 1.1 joerg // Create and execute the frontend to generate an LLVM bitcode module. 210 1.1 joerg std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction()); 211 1.1 joerg if (!Clang.ExecuteAction(*Act)) 212 1.1 joerg return 1; 213 1.1 joerg 214 1.1 joerg llvm::InitializeNativeTarget(); 215 1.1 joerg llvm::InitializeNativeTargetAsmPrinter(); 216 1.1 joerg 217 1.1 joerg int Res = 255; 218 1.1 joerg std::unique_ptr<llvm::LLVMContext> Ctx(Act->takeLLVMContext()); 219 1.1 joerg std::unique_ptr<llvm::Module> Module = Act->takeModule(); 220 1.1 joerg 221 1.1 joerg if (Module) { 222 1.1 joerg auto J = ExitOnErr(llvm::orc::SimpleJIT::Create()); 223 1.1 joerg 224 1.1 joerg ExitOnErr(J->addModule( 225 1.1 joerg llvm::orc::ThreadSafeModule(std::move(Module), std::move(Ctx)))); 226 1.1 joerg auto Main = (int (*)(...))ExitOnErr(J->getSymbolAddress("main")); 227 1.1 joerg Res = Main(); 228 1.1 joerg } 229 1.1 joerg 230 1.1 joerg // Shutdown. 231 1.1 joerg llvm::llvm_shutdown(); 232 1.1 joerg 233 1.1 joerg return Res; 234 1.1 joerg } 235