|  | //===-- examples/clang-interpreter/main.cpp - Clang C Interpreter Example -===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/Basic/DiagnosticOptions.h" | 
|  | #include "clang/CodeGen/CodeGenAction.h" | 
|  | #include "clang/Driver/Compilation.h" | 
|  | #include "clang/Driver/Driver.h" | 
|  | #include "clang/Driver/Tool.h" | 
|  | #include "clang/Frontend/CompilerInstance.h" | 
|  | #include "clang/Frontend/CompilerInvocation.h" | 
|  | #include "clang/Frontend/FrontendDiagnostic.h" | 
|  | #include "clang/Frontend/TextDiagnosticPrinter.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/ExecutionEngine/ExecutionEngine.h" | 
|  | #include "llvm/ExecutionEngine/Orc/CompileUtils.h" | 
|  | #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" | 
|  | #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" | 
|  | #include "llvm/ExecutionEngine/SectionMemoryManager.h" | 
|  | #include "llvm/IR/DataLayout.h" | 
|  | #include "llvm/IR/Mangler.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/Support/FileSystem.h" | 
|  | #include "llvm/Support/Host.h" | 
|  | #include "llvm/Support/ManagedStatic.h" | 
|  | #include "llvm/Support/Path.h" | 
|  | #include "llvm/Support/TargetSelect.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include "llvm/Target/TargetMachine.h" | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace clang::driver; | 
|  |  | 
|  | // This function isn't referenced outside its translation unit, but it | 
|  | // can't use the "static" keyword because its address is used for | 
|  | // GetMainExecutable (since some platforms don't support taking the | 
|  | // address of main, and some platforms can't implement GetMainExecutable | 
|  | // without being given the address of a function in the main executable). | 
|  | std::string GetExecutablePath(const char *Argv0, void *MainAddr) { | 
|  | return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); | 
|  | } | 
|  |  | 
|  | namespace llvm { | 
|  | namespace orc { | 
|  |  | 
|  | class SimpleJIT { | 
|  | private: | 
|  | ExecutionSession ES; | 
|  | std::shared_ptr<SymbolResolver> Resolver; | 
|  | std::unique_ptr<TargetMachine> TM; | 
|  | const DataLayout DL; | 
|  | RTDyldObjectLinkingLayer ObjectLayer; | 
|  | IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer; | 
|  |  | 
|  | public: | 
|  | SimpleJIT() | 
|  | : Resolver(createLegacyLookupResolver( | 
|  | ES, | 
|  | [this](const std::string &Name) -> JITSymbol { | 
|  | if (auto Sym = CompileLayer.findSymbol(Name, false)) | 
|  | return Sym; | 
|  | else if (auto Err = Sym.takeError()) | 
|  | return std::move(Err); | 
|  | if (auto SymAddr = | 
|  | RTDyldMemoryManager::getSymbolAddressInProcess(Name)) | 
|  | return JITSymbol(SymAddr, JITSymbolFlags::Exported); | 
|  | return nullptr; | 
|  | }, | 
|  | [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })), | 
|  | TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), | 
|  | ObjectLayer(ES, | 
|  | [this](VModuleKey) { | 
|  | return RTDyldObjectLinkingLayer::Resources{ | 
|  | std::make_shared<SectionMemoryManager>(), Resolver}; | 
|  | }), | 
|  | CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { | 
|  | llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); | 
|  | } | 
|  |  | 
|  | const TargetMachine &getTargetMachine() const { return *TM; } | 
|  |  | 
|  | VModuleKey addModule(std::unique_ptr<Module> M) { | 
|  | // Add the module to the JIT with a new VModuleKey. | 
|  | auto K = ES.allocateVModule(); | 
|  | cantFail(CompileLayer.addModule(K, std::move(M))); | 
|  | return K; | 
|  | } | 
|  |  | 
|  | JITSymbol findSymbol(const StringRef &Name) { | 
|  | std::string MangledName; | 
|  | raw_string_ostream MangledNameStream(MangledName); | 
|  | Mangler::getNameWithPrefix(MangledNameStream, Name, DL); | 
|  | return CompileLayer.findSymbol(MangledNameStream.str(), true); | 
|  | } | 
|  |  | 
|  | JITTargetAddress getSymbolAddress(const StringRef &Name) { | 
|  | return cantFail(findSymbol(Name).getAddress()); | 
|  | } | 
|  |  | 
|  | void removeModule(VModuleKey K) { | 
|  | cantFail(CompileLayer.removeModule(K)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // end namespace orc | 
|  | } // end namespace llvm | 
|  |  | 
|  | int main(int argc, const char **argv) { | 
|  | // This just needs to be some symbol in the binary; C++ doesn't | 
|  | // allow taking the address of ::main however. | 
|  | void *MainAddr = (void*) (intptr_t) GetExecutablePath; | 
|  | std::string Path = GetExecutablePath(argv[0], MainAddr); | 
|  | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); | 
|  | TextDiagnosticPrinter *DiagClient = | 
|  | new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); | 
|  |  | 
|  | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); | 
|  | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); | 
|  |  | 
|  | const std::string TripleStr = llvm::sys::getProcessTriple(); | 
|  | llvm::Triple T(TripleStr); | 
|  |  | 
|  | // Use ELF on Windows-32 and MingW for now. | 
|  | #ifndef CLANG_INTERPRETER_COFF_FORMAT | 
|  | if (T.isOSBinFormatCOFF()) | 
|  | T.setObjectFormat(llvm::Triple::ELF); | 
|  | #endif | 
|  |  | 
|  | Driver TheDriver(Path, T.str(), Diags); | 
|  | TheDriver.setTitle("clang interpreter"); | 
|  | TheDriver.setCheckInputsExist(false); | 
|  |  | 
|  | // FIXME: This is a hack to try to force the driver to do something we can | 
|  | // recognize. We need to extend the driver library to support this use model | 
|  | // (basically, exactly one input, and the operation mode is hard wired). | 
|  | SmallVector<const char *, 16> Args(argv, argv + argc); | 
|  | Args.push_back("-fsyntax-only"); | 
|  | std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args)); | 
|  | if (!C) | 
|  | return 0; | 
|  |  | 
|  | // FIXME: This is copied from ASTUnit.cpp; simplify and eliminate. | 
|  |  | 
|  | // We expect to get back exactly one command job, if we didn't something | 
|  | // failed. Extract that job from the compilation. | 
|  | const driver::JobList &Jobs = C->getJobs(); | 
|  | if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { | 
|  | SmallString<256> Msg; | 
|  | llvm::raw_svector_ostream OS(Msg); | 
|  | Jobs.Print(OS, "; ", true); | 
|  | Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin()); | 
|  | if (llvm::StringRef(Cmd.getCreator().getName()) != "clang") { | 
|  | Diags.Report(diag::err_fe_expected_clang_command); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | // Initialize a compiler invocation object from the clang (-cc1) arguments. | 
|  | const driver::ArgStringList &CCArgs = Cmd.getArguments(); | 
|  | std::unique_ptr<CompilerInvocation> CI(new CompilerInvocation); | 
|  | CompilerInvocation::CreateFromArgs(*CI, | 
|  | const_cast<const char **>(CCArgs.data()), | 
|  | const_cast<const char **>(CCArgs.data()) + | 
|  | CCArgs.size(), | 
|  | Diags); | 
|  |  | 
|  | // Show the invocation, with -v. | 
|  | if (CI->getHeaderSearchOpts().Verbose) { | 
|  | llvm::errs() << "clang invocation:\n"; | 
|  | Jobs.Print(llvm::errs(), "\n", true); | 
|  | llvm::errs() << "\n"; | 
|  | } | 
|  |  | 
|  | // FIXME: This is copied from cc1_main.cpp; simplify and eliminate. | 
|  |  | 
|  | // Create a compiler instance to handle the actual work. | 
|  | CompilerInstance Clang; | 
|  | Clang.setInvocation(std::move(CI)); | 
|  |  | 
|  | // Create the compilers actual diagnostics engine. | 
|  | Clang.createDiagnostics(); | 
|  | if (!Clang.hasDiagnostics()) | 
|  | return 1; | 
|  |  | 
|  | // Infer the builtin include path if unspecified. | 
|  | if (Clang.getHeaderSearchOpts().UseBuiltinIncludes && | 
|  | Clang.getHeaderSearchOpts().ResourceDir.empty()) | 
|  | Clang.getHeaderSearchOpts().ResourceDir = | 
|  | CompilerInvocation::GetResourcesPath(argv[0], MainAddr); | 
|  |  | 
|  | // Create and execute the frontend to generate an LLVM bitcode module. | 
|  | std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction()); | 
|  | if (!Clang.ExecuteAction(*Act)) | 
|  | return 1; | 
|  |  | 
|  | llvm::InitializeNativeTarget(); | 
|  | llvm::InitializeNativeTargetAsmPrinter(); | 
|  |  | 
|  | int Res = 255; | 
|  | std::unique_ptr<llvm::Module> Module = Act->takeModule(); | 
|  |  | 
|  | if (Module) { | 
|  | llvm::orc::SimpleJIT J; | 
|  | auto H = J.addModule(std::move(Module)); | 
|  | auto Main = (int(*)(...))J.getSymbolAddress("main"); | 
|  | Res = Main(); | 
|  | J.removeModule(H); | 
|  | } | 
|  |  | 
|  | // Shutdown. | 
|  | llvm::llvm_shutdown(); | 
|  |  | 
|  | return Res; | 
|  | } |