Home | History | Annotate | Line # | Download | only in clang-interpreter
      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