summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
commit486754660bb926339aefcf012a3f848592babb8b (patch)
treeecdbc446c9876f4f120f701c243373cd3cb43db3 /examples
parent55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff)
Notes
Diffstat (limited to 'examples')
-rw-r--r--examples/PrintFunctionNames/CMakeLists.txt2
-rw-r--r--examples/analyzer-plugin/MainCallChecker.cpp4
-rw-r--r--examples/clang-interpreter/CMakeLists.txt67
-rw-r--r--examples/clang-interpreter/README.txt7
-rw-r--r--examples/clang-interpreter/Test.cxx34
-rw-r--r--examples/clang-interpreter/main.cpp129
6 files changed, 196 insertions, 47 deletions
diff --git a/examples/PrintFunctionNames/CMakeLists.txt b/examples/PrintFunctionNames/CMakeLists.txt
index f5f818866ca60..e582b2c45a861 100644
--- a/examples/PrintFunctionNames/CMakeLists.txt
+++ b/examples/PrintFunctionNames/CMakeLists.txt
@@ -1,7 +1,7 @@
# If we don't need RTTI or EH, there's no reason to export anything
# from the plugin.
if( NOT MSVC ) # MSVC mangles symbols differently, and
- # PrintFunctionNames.export contains C++ symbols.
+ # PrintFunctionNames.export contains C++ symbols.
if( NOT LLVM_REQUIRES_RTTI )
if( NOT LLVM_REQUIRES_EH )
set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/PrintFunctionNames.exports)
diff --git a/examples/analyzer-plugin/MainCallChecker.cpp b/examples/analyzer-plugin/MainCallChecker.cpp
index 7f08760e3d4ce..74fe663e981f5 100644
--- a/examples/analyzer-plugin/MainCallChecker.cpp
+++ b/examples/analyzer-plugin/MainCallChecker.cpp
@@ -16,10 +16,8 @@ public:
} // end anonymous namespace
void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
- const ProgramStateRef state = C.getState();
- const LocationContext *LC = C.getLocationContext();
const Expr *Callee = CE->getCallee();
- const FunctionDecl *FD = state->getSVal(Callee, LC).getAsFunctionDecl();
+ const FunctionDecl *FD = C.getSVal(Callee).getAsFunctionDecl();
if (!FD)
return;
diff --git a/examples/clang-interpreter/CMakeLists.txt b/examples/clang-interpreter/CMakeLists.txt
index 3084238844802..7b9657ec1abf5 100644
--- a/examples/clang-interpreter/CMakeLists.txt
+++ b/examples/clang-interpreter/CMakeLists.txt
@@ -3,7 +3,10 @@ set(LLVM_LINK_COMPONENTS
ExecutionEngine
MC
MCJIT
+ Object
+ OrcJit
Option
+ RuntimeDyld
Support
native
)
@@ -23,3 +26,67 @@ target_link_libraries(clang-interpreter
clangDriver
clangFrontend
)
+
+export_executable_symbols(clang-interpreter)
+
+if (MSVC)
+ # Is this a CMake bug that even with export_executable_symbols, Windows
+ # needs to explictly export the type_info vtable
+ set_property(TARGET clang-interpreter
+ APPEND_STRING PROPERTY LINK_FLAGS " /EXPORT:??_7type_info@@6B@")
+endif()
+
+function(clang_enable_exceptions TARGET)
+ # Really have to jump through hoops to enable exception handling independent
+ # of how LLVM is being built.
+ if (NOT LLVM_REQUIRES_EH AND NOT LLVM_REQUIRES_RTTI)
+ if (MSVC)
+ # /EHs to allow throwing from extern "C"
+ set(excptnExceptions_ON "/D _HAS_EXCEPTIONS=1 /EHs /wd4714")
+ set(excptnExceptions_OFF "/D _HAS_EXCEPTIONS=0 /EHs-c-")
+ set(excptnRTTI_ON "/GR")
+ set(excptnRTTI_OFF "/GR-")
+ set(excptnEHRTTIRegEx "(/EHs(-c-?)|_HAS_EXCEPTIONS=(0|1))")
+ else()
+ set(excptnExceptions_ON "-fexceptions")
+ set(excptnExceptions_OFF "-fno-exceptions")
+ set(excptnRTTI_ON "-frtti")
+ set(excptnRTTI_OFF "-fno-rtti")
+ set(excptnEHRTTIRegEx "-f(exceptions|no-exceptions)")
+ endif()
+ if (LLVM_REQUIRES_EH)
+ set(excptnExceptions_DFLT ${excptnExceptions_ON})
+ else()
+ set(excptnExceptions_DFLT ${excptnExceptions_OFF})
+ endif()
+ if (LLVM_REQUIRES_RTTI)
+ set(excptnRTTI_DFLT ${excptnRTTI_ON})
+ else()
+ set(excptnRTTI_DFLT ${excptnRTTI_OFF})
+ endif()
+
+ # Strip the exception & rtti flags from the target
+ get_property(addedFlags TARGET ${TARGET} PROPERTY COMPILE_FLAGS)
+ string(REGEX REPLACE ${excptnEHRTTIRegEx} "" editedFlags "${addedFlags}")
+ string(REPLACE ${excptnRTTI_OFF} "" editedFlags "${editedFlags}")
+ set_property(TARGET ${TARGET} PROPERTY COMPILE_FLAGS "${editedFlags}")
+
+ get_property(addedFlags TARGET ${TARGET} PROPERTY COMPILE_DEFINITIONS)
+ string(REGEX REPLACE ${excptnEHRTTIRegEx} "" editedFlags "${addedFlags}")
+ string(REPLACE ${excptnRTTI_OFF} "" editedFlags "${editedFlags}")
+ set_property(TARGET ${TARGET} PROPERTY COMPILE_DEFINITIONS "${editedFlags}")
+
+ # Re-add the exception & rtti flags from LLVM
+ set_property(SOURCE main.cpp APPEND_STRING PROPERTY COMPILE_FLAGS
+ " ${excptnExceptions_DFLT} ${excptnRTTI_DFLT} ")
+ set_property(SOURCE Manager.cpp APPEND_STRING PROPERTY COMPILE_FLAGS
+ " ${excptnExceptions_DFLT} ${excptnRTTI_DFLT} ")
+
+ # Invoke with exceptions & rtti
+ set_property(SOURCE Invoke.cpp APPEND_STRING PROPERTY COMPILE_FLAGS
+ " ${excptnExceptions_ON} ${excptnRTTI_ON} ")
+
+ endif()
+endfunction(clang_enable_exceptions)
+
+clang_enable_exceptions(clang-interpreter)
diff --git a/examples/clang-interpreter/README.txt b/examples/clang-interpreter/README.txt
index 7dd45fad50483..b4f8a935cef83 100644
--- a/examples/clang-interpreter/README.txt
+++ b/examples/clang-interpreter/README.txt
@@ -1,4 +1,4 @@
-This is an example of Clang based interpreter, for executing standalone C
+This is an example of Clang based interpreter, for executing standalone C/C++
programs.
It demonstrates the following features:
@@ -12,6 +12,9 @@ It demonstrates the following features:
4. Use the LLVM JIT functionality to execute the final module.
+ 5. Intercepting a Win64 library call to allow throwing and catching exceptions
+ in and from the JIT.
+
The implementation has many limitations and is not designed to be a full fledged
-C interpreter. It is designed to demonstrate a simple but functional use of the
+interpreter. It is designed to demonstrate a simple but functional use of the
Clang compiler libraries.
diff --git a/examples/clang-interpreter/Test.cxx b/examples/clang-interpreter/Test.cxx
new file mode 100644
index 0000000000000..d2cbb0baac5c2
--- /dev/null
+++ b/examples/clang-interpreter/Test.cxx
@@ -0,0 +1,34 @@
+//===-- examples/clang-interpreter/Test.cxx - 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.
+//
+//===----------------------------------------------------------------------===//
+
+// Example throwing in and from the JIT (particularly on Win64).
+//
+// ./bin/clang-interpreter <src>/tools/clang/examples/clang-interpreter/Test.cxx
+
+#include <stdexcept>
+#include <stdio.h>
+
+static void ThrowerAnError(const char* Name) {
+ throw std::runtime_error(Name);
+}
+
+int main(int argc, const char** argv) {
+ for (int I = 0; I < argc; ++I)
+ printf("arg[%d]='%s'\n", I, argv[I]);
+
+ try {
+ ThrowerAnError("In JIT");
+ } catch (const std::exception& E) {
+ printf("Caught: '%s'\n", E.what());
+ } catch (...) {
+ printf("Unknown exception\n");
+ }
+ ThrowerAnError("From JIT");
+ return 0;
+}
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index f7832291f2b62..3f87be29a9794 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/CodeGen/CodeGenAction.h"
#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"
@@ -18,7 +18,12 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
-#include "llvm/ExecutionEngine/MCJIT.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"
@@ -26,7 +31,8 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
-#include <memory>
+#include "llvm/Target/TargetMachine.h"
+
using namespace clang;
using namespace clang::driver;
@@ -35,51 +41,80 @@ using namespace clang::driver;
// 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) {
- // 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 GetExecutablePath(const char *Argv0, void *MainAddr) {
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}
-static llvm::ExecutionEngine *
-createExecutionEngine(std::unique_ptr<llvm::Module> M, std::string *ErrorStr) {
- return llvm::EngineBuilder(std::move(M))
- .setEngineKind(llvm::EngineKind::Either)
- .setErrorStr(ErrorStr)
- .create();
-}
+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);
+ }
-static int Execute(std::unique_ptr<llvm::Module> Mod, char *const *envp) {
- llvm::InitializeNativeTarget();
- llvm::InitializeNativeTargetAsmPrinter();
+ 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;
+ }
- llvm::Module &M = *Mod;
- std::string Error;
- std::unique_ptr<llvm::ExecutionEngine> EE(
- createExecutionEngine(std::move(Mod), &Error));
- if (!EE) {
- llvm::errs() << "unable to make execution engine: " << Error << "\n";
- return 255;
+ JITSymbol findSymbol(const StringRef &Name) {
+ std::string MangledName;
+ raw_string_ostream MangledNameStream(MangledName);
+ Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
+ return CompileLayer.findSymbol(MangledNameStream.str(), true);
}
- llvm::Function *EntryFn = M.getFunction("main");
- if (!EntryFn) {
- llvm::errs() << "'main' function not found in module.\n";
- return 255;
+ JITTargetAddress getSymbolAddress(const StringRef &Name) {
+ return cantFail(findSymbol(Name).getAddress());
}
- // FIXME: Support passing arguments.
- std::vector<std::string> Args;
- Args.push_back(M.getModuleIdentifier());
+ void removeModule(VModuleKey K) {
+ cantFail(CompileLayer.removeModule(K));
+ }
+};
- EE->finalizeObject();
- return EE->runFunctionAsMain(EntryFn, Args, envp);
-}
+} // end namespace orc
+} // end namespace llvm
-int main(int argc, const char **argv, char * const *envp) {
+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]);
+ std::string Path = GetExecutablePath(argv[0], MainAddr);
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
@@ -87,11 +122,14 @@ int main(int argc, const char **argv, char * const *envp) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
- // Use ELF on windows for now.
- std::string TripleStr = llvm::sys::getProcessTriple();
+ 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");
@@ -163,12 +201,21 @@ int main(int argc, const char **argv, char * const *envp) {
if (!Clang.ExecuteAction(*Act))
return 1;
+ llvm::InitializeNativeTarget();
+ llvm::InitializeNativeTargetAsmPrinter();
+
int Res = 255;
- if (std::unique_ptr<llvm::Module> Module = Act->takeModule())
- Res = Execute(std::move(Module), envp);
+ 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;