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