mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-02 08:01:11 +03:00
Make LDC custom passes available to jit, add API for jit compiler options (#2758)
This commit is contained in:
parent
b6d8210255
commit
a40c6c7fd2
22 changed files with 478 additions and 27 deletions
|
@ -440,6 +440,7 @@ include(HandleLTOPGOBuildOptions)
|
|||
# Enable Dynamic compilation if supported for this platform and LLVM version.
|
||||
#
|
||||
set(LDC_DYNAMIC_COMPILE "AUTO" CACHE STRING "Support dynamic compilation (True|False). Enabled by default.")
|
||||
option(LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES "Use custom LDC passes in jit" ON)
|
||||
if(LDC_DYNAMIC_COMPILE STREQUAL "AUTO")
|
||||
set(LDC_DYNAMIC_COMPILE False) # must be a valid Python boolean constant (case sensitive)
|
||||
if (NOT (LDC_LLVM_VER LESS 500))
|
||||
|
|
9
LICENSE
9
LICENSE
|
@ -23,8 +23,13 @@ Libraries (lib/ and import/ in binary packages):
|
|||
Phobos (runtime/phobos), is distributed under the terms of the Boost
|
||||
Software License. See the individual source files for author information.
|
||||
|
||||
- The ldc-jit-rt library is distributed under the terms of the
|
||||
Boost Software license (but additionally makes use of LLVM code).
|
||||
- Most of the ldc-jit-rt library is licensed under the terms of the
|
||||
Boost Software license. Additionally it contains code derived from LLVM
|
||||
governed by the University of Illinois Open Source License.
|
||||
Finally, it incorporates code from the LDC compiler (gen/passes/* and parts
|
||||
of gen/optimizer.cpp) which are under "three-clause BSD" LDC license. These
|
||||
parts from the LDC compiler can be omitted if you build ldc-jit-rt with
|
||||
LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES=OFF.
|
||||
|
||||
- The profile-rt runtime library (runtime/profile-rt) is a copy of LLVM's
|
||||
compiler-rt/profile library with a small D source addition. It is dual
|
||||
|
|
|
@ -42,10 +42,10 @@
|
|||
#include "gen/llvm.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/metadata.h"
|
||||
#include "gen/modules.h"
|
||||
#include "gen/objcgen.h"
|
||||
#include "gen/optimizer.h"
|
||||
#include "gen/passes/metadata.h"
|
||||
#include "gen/passes/Passes.h"
|
||||
#include "gen/runtime.h"
|
||||
#include "gen/uda.h"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "gen/dcompute/target.h"
|
||||
#include "gen/dcompute/druntime.h"
|
||||
#include "gen/metadata.h"
|
||||
#include "gen/passes/metadata.h"
|
||||
#include "gen/abi-nvptx.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/optimizer.h"
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#endif
|
||||
|
||||
#include "gen/attributes.h"
|
||||
#include "gen/metadata.h"
|
||||
#include "metadata.h"
|
||||
#include "gen/passes/Passes.h"
|
||||
#include "gen/runtime.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
@ -849,7 +849,7 @@ bool isSafeToStackAllocate(BasicBlock::iterator Alloc, Value *V,
|
|||
const unsigned paramHasAttr_firstArg = 0;
|
||||
#endif
|
||||
if (!CS.paramHasAttr(A - B + paramHasAttr_firstArg,
|
||||
LLAttribute::NoCapture)) {
|
||||
llvm::Attribute::AttrKind::NoCapture)) {
|
||||
// The parameter is not marked 'nocapture' - captured.
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "gen/metadata.h"
|
||||
|
||||
namespace llvm {
|
||||
class FunctionPass;
|
||||
class ModulePass;
|
||||
|
|
|
@ -206,6 +206,33 @@ struct LLVM_LIBRARY_VISIBILITY AllocationOpt : public LibCallOptimization {
|
|||
}
|
||||
};
|
||||
|
||||
// This module will also be used in jit runtime
|
||||
// copy these function here to avoid dependencies on rest of compiler
|
||||
LLIntegerType *DtoSize_t(llvm::LLVMContext &context,
|
||||
const llvm::Triple &triple) {
|
||||
// the type of size_t does not change once set
|
||||
static LLIntegerType *t = nullptr;
|
||||
if (t == nullptr) {
|
||||
|
||||
if (triple.isArch64Bit()) {
|
||||
t = LLType::getInt64Ty(context);
|
||||
} else if (triple.isArch32Bit()) {
|
||||
t = LLType::getInt32Ty(context);
|
||||
} else if (triple.isArch16Bit()) {
|
||||
t = LLType::getInt16Ty(context);
|
||||
} else {
|
||||
llvm_unreachable("Unsupported size_t width");
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
llvm::ConstantInt *DtoConstSize_t(llvm::LLVMContext &context,
|
||||
const llvm::Triple &targetTriple,
|
||||
uint64_t i) {
|
||||
return LLConstantInt::get(DtoSize_t(context, targetTriple), i, false);
|
||||
}
|
||||
|
||||
/// ArraySliceCopyOpt - Turn slice copies into llvm.memcpy when safe
|
||||
struct LLVM_LIBRARY_VISIBILITY ArraySliceCopyOpt : public LibCallOptimization {
|
||||
Value *CallOptimizer(Function *Callee, CallInst *CI,
|
||||
|
@ -244,9 +271,12 @@ struct LLVM_LIBRARY_VISIBILITY ArraySliceCopyOpt : public LibCallOptimization {
|
|||
|
||||
// Equal length and the pointers definitely don't alias, so it's safe to
|
||||
// replace the call with memcpy
|
||||
auto Size = Sz != llvm::MemoryLocation::UnknownSize
|
||||
? DtoConstSize_t(Sz)
|
||||
: B.CreateMul(DstLength, ElemSz);
|
||||
auto Size =
|
||||
Sz != llvm::MemoryLocation::UnknownSize
|
||||
? DtoConstSize_t(
|
||||
Callee->getContext(),
|
||||
llvm::Triple(Callee->getParent()->getTargetTriple()), Sz)
|
||||
: B.CreateMul(DstLength, ElemSz);
|
||||
return EmitMemCpy(CI->getOperand(0), CI->getOperand(2), Size, 1, B);
|
||||
}
|
||||
};
|
||||
|
@ -391,7 +421,7 @@ bool SimplifyDRuntimeCalls::runOnce(Function &F, const DataLayout *DL,
|
|||
}
|
||||
|
||||
LLVM_DEBUG(errs() << "SimplifyDRuntimeCalls simplified: " << *CI;
|
||||
errs() << " into: " << *Result << "\n");
|
||||
errs() << " into: " << *Result << "\n");
|
||||
|
||||
// Something changed!
|
||||
Changed = true;
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/mangling.h"
|
||||
#include "gen/metadata.h"
|
||||
#include "gen/passes/metadata.h"
|
||||
#include "gen/pragma.h"
|
||||
#include "gen/rttibuilder.h"
|
||||
#include "gen/runtime.h"
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "gen/logger.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/mangling.h"
|
||||
#include "gen/metadata.h"
|
||||
#include "gen/passes/metadata.h"
|
||||
#include "gen/pragma.h"
|
||||
#include "gen/runtime.h"
|
||||
#include "gen/tollvm.h"
|
||||
|
|
|
@ -6,6 +6,14 @@ if(LDC_DYNAMIC_COMPILE)
|
|||
file(GLOB LDC_JITRT_H ${JITRT_DIR}/cpp/*.h)
|
||||
file(GLOB LDC_JITRT_SO_CXX ${JITRT_DIR}/cpp-so/*.cpp)
|
||||
file(GLOB LDC_JITRT_SO_H ${JITRT_DIR}/cpp-so/*.h)
|
||||
message(STATUS "Use custom passes in jit: ${LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES}")
|
||||
if(LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES)
|
||||
file(GLOB LDC_JITRT_SO_PASSES_CXX ${CMAKE_SOURCE_DIR}/gen/passes/*.cpp)
|
||||
file(GLOB LDC_JITRT_SO_PASSES_H ${CMAKE_SOURCE_DIR}/gen/passes/*.h)
|
||||
else()
|
||||
set(LDC_JITRT_SO_PASSES_CXX "")
|
||||
set(LDC_JITRT_SO_PASSES_H "")
|
||||
endif()
|
||||
|
||||
# Set compiler-dependent flags
|
||||
if(MSVC)
|
||||
|
@ -61,7 +69,7 @@ if(LDC_DYNAMIC_COMPILE)
|
|||
get_target_suffix("" "${path_suffix}" target_suffix)
|
||||
set(output_path ${CMAKE_BINARY_DIR}/lib${path_suffix})
|
||||
|
||||
add_library(ldc-jit-rt-so${target_suffix} SHARED ${LDC_JITRT_SO_CXX} ${LDC_JITRT_SO_H})
|
||||
add_library(ldc-jit-rt-so${target_suffix} SHARED ${LDC_JITRT_SO_CXX} ${LDC_JITRT_SO_H} ${LDC_JITRT_SO_PASSES_CXX} ${LDC_JITRT_SO_PASSES_H})
|
||||
set_common_library_properties(ldc-jit-rt-so${target_suffix}
|
||||
ldc-jit ${output_path}
|
||||
"${c_flags} ${LDC_CXXFLAGS} ${LLVM_CXXFLAGS} ${JITRT_EXTRA_FLAGS}"
|
||||
|
@ -70,6 +78,13 @@ if(LDC_DYNAMIC_COMPILE)
|
|||
)
|
||||
set_target_properties(ldc-jit-rt-so${target_suffix} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
if(LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES)
|
||||
target_compile_definitions(ldc-jit-rt-so${target_suffix} PRIVATE LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES)
|
||||
endif()
|
||||
|
||||
target_include_directories(ldc-jit-rt-so${target_suffix}
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/gen/passes/)
|
||||
|
||||
target_link_libraries(ldc-jit-rt-so${target_suffix} ${JITRT_LLVM_LIBS})
|
||||
|
||||
set(jitrt_d_o "")
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "context.h"
|
||||
#include "jit_context.h"
|
||||
#include "optimizer.h"
|
||||
#include "options.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "llvm/Bitcode/BitcodeReader.h"
|
||||
|
@ -461,4 +462,11 @@ EXTERNAL void JIT_UNREG_BIND_PAYLOAD(void *handle) {
|
|||
JITContext &myJit = getJit();
|
||||
myJit.unregisterBind(handle);
|
||||
}
|
||||
|
||||
EXTERNAL bool JIT_SET_OPTS(const Slice<Slice<const char>> *args,
|
||||
void (*errs)(void *, const char *, size_t),
|
||||
void *errsContext) {
|
||||
assert(args != nullptr);
|
||||
return parseOptions(*args, errs, errsContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "param_slice.h"
|
||||
|
||||
#include "slice.h"
|
||||
|
||||
enum class DumpStage : int {
|
||||
OriginalModule = 0,
|
||||
MergedModule = 1,
|
||||
|
@ -43,6 +45,8 @@ enum { ApiVersion = LDC_DYNAMIC_COMPILE_API_VERSION };
|
|||
#define JIT_UNREG_BIND_PAYLOAD \
|
||||
MAKE_JIT_API_CALL(unregisterBindPayloadImplSo, \
|
||||
LDC_DYNAMIC_COMPILE_API_VERSION)
|
||||
#define JIT_SET_OPTS \
|
||||
MAKE_JIT_API_CALL(setDynamicCompilerOptsImpl, LDC_DYNAMIC_COMPILE_API_VERSION)
|
||||
|
||||
typedef void (*InterruptPointHandlerT)(void *, const char *action,
|
||||
const char *object);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
//
|
||||
// This file is distributed under the Boost Software License. See the LICENSE
|
||||
// file for details.
|
||||
// Uses some parts from gen/optimizer.cpp which is under the BSD-style LDC
|
||||
// license.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
@ -22,6 +24,8 @@
|
|||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/IPO/AlwaysInliner.h"
|
||||
#include "llvm/Transforms/IPO/Inliner.h"
|
||||
|
@ -31,7 +35,86 @@
|
|||
#include "utils.h"
|
||||
#include "valueparser.h"
|
||||
|
||||
#ifdef LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES
|
||||
#include "Passes.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
namespace cl = llvm::cl;
|
||||
cl::opt<bool>
|
||||
verifyEach("verify-each", cl::ZeroOrMore, cl::Hidden,
|
||||
cl::desc("Run verifier after D-specific and explicitly "
|
||||
"specified optimization passes"));
|
||||
|
||||
/// LDC LICENSE START
|
||||
#ifdef LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES
|
||||
cl::opt<bool>
|
||||
disableLangSpecificPasses("disable-d-passes", cl::ZeroOrMore,
|
||||
cl::desc("Disable all D-specific passes"));
|
||||
|
||||
cl::opt<bool> disableSimplifyDruntimeCalls(
|
||||
"disable-simplify-drtcalls", cl::ZeroOrMore,
|
||||
cl::desc("Disable simplification of druntime calls"));
|
||||
|
||||
cl::opt<bool> disableSimplifyLibCalls(
|
||||
"disable-simplify-libcalls", cl::ZeroOrMore,
|
||||
cl::desc("Disable simplification of well-known C runtime calls"));
|
||||
|
||||
cl::opt<bool> disableGCToStack(
|
||||
"disable-gc2stack", cl::ZeroOrMore,
|
||||
cl::desc("Disable promotion of GC allocations to stack memory"));
|
||||
#endif
|
||||
/// LDC LICENSE END
|
||||
|
||||
cl::opt<bool> stripDebug(
|
||||
"strip-debug", cl::ZeroOrMore,
|
||||
cl::desc("Strip symbolic debug information before optimization"));
|
||||
|
||||
cl::opt<bool> disableLoopUnrolling(
|
||||
"disable-loop-unrolling", cl::ZeroOrMore,
|
||||
cl::desc("Disable loop unrolling in all relevant passes"));
|
||||
cl::opt<bool>
|
||||
disableLoopVectorization("disable-loop-vectorization", cl::ZeroOrMore,
|
||||
cl::desc("Disable the loop vectorization pass"));
|
||||
|
||||
cl::opt<bool>
|
||||
disableSLPVectorization("disable-slp-vectorization", cl::ZeroOrMore,
|
||||
cl::desc("Disable the slp vectorization pass"));
|
||||
|
||||
/// LDC LICENSE START
|
||||
#ifdef LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES
|
||||
void addPass(llvm::PassManagerBase &pm, llvm::Pass *pass) {
|
||||
pm.add(pass);
|
||||
|
||||
if (verifyEach) {
|
||||
pm.add(llvm::createVerifierPass());
|
||||
}
|
||||
}
|
||||
|
||||
void addStripExternalsPass(const llvm::PassManagerBuilder &builder,
|
||||
llvm::PassManagerBase &pm) {
|
||||
if (builder.OptLevel >= 1) {
|
||||
addPass(pm, createStripExternalsPass());
|
||||
addPass(pm, llvm::createGlobalDCEPass());
|
||||
}
|
||||
}
|
||||
|
||||
void addSimplifyDRuntimeCallsPass(const llvm::PassManagerBuilder &builder,
|
||||
llvm::PassManagerBase &pm) {
|
||||
if (builder.OptLevel >= 2 && builder.SizeLevel == 0) {
|
||||
addPass(pm, createSimplifyDRuntimeCalls());
|
||||
}
|
||||
}
|
||||
|
||||
void addGarbageCollect2StackPass(const llvm::PassManagerBuilder &builder,
|
||||
llvm::PassManagerBase &pm) {
|
||||
if (builder.OptLevel >= 2 && builder.SizeLevel == 0) {
|
||||
addPass(pm, createGarbageCollect2Stack());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/// LDC LICENSE END
|
||||
|
||||
// TODO: share this function with compiler
|
||||
void addOptimizationPasses(llvm::legacy::PassManagerBase &mpm,
|
||||
llvm::legacy::FunctionPassManager &fpm,
|
||||
|
@ -57,26 +140,43 @@ void addOptimizationPasses(llvm::legacy::PassManagerBase &mpm,
|
|||
}
|
||||
builder.DisableUnitAtATime = false;
|
||||
|
||||
// TODO: Expose this option
|
||||
builder.DisableUnrollLoops = optLevel == 0;
|
||||
builder.DisableUnrollLoops = (disableLoopUnrolling.getNumOccurrences() > 0)
|
||||
? disableLoopUnrolling
|
||||
: optLevel == 0;
|
||||
|
||||
// TODO: expose this option
|
||||
if (/*disableLoopVectorization*/ false) {
|
||||
if (disableLoopVectorization) {
|
||||
builder.LoopVectorize = false;
|
||||
// If option wasn't forced via cmd line (-vectorize-loops, -loop-vectorize)
|
||||
} else if (!builder.LoopVectorize) {
|
||||
builder.LoopVectorize = optLevel > 1 && sizeLevel < 2;
|
||||
}
|
||||
|
||||
// TODO: expose this option
|
||||
builder.SLPVectorize =
|
||||
/*disableSLPVectorization*/ false ? false : optLevel > 1 && sizeLevel < 2;
|
||||
disableSLPVectorization ? false : optLevel > 1 && sizeLevel < 2;
|
||||
|
||||
// TODO: sanitizers support in jit?
|
||||
// TODO: lang specific passes support
|
||||
// TODO: addStripExternalsPass?
|
||||
// TODO: PGO support in jit?
|
||||
|
||||
/// LDC LICENSE START
|
||||
#ifdef LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES
|
||||
if (!disableLangSpecificPasses) {
|
||||
if (!disableSimplifyDruntimeCalls) {
|
||||
builder.addExtension(llvm::PassManagerBuilder::EP_LoopOptimizerEnd,
|
||||
addSimplifyDRuntimeCallsPass);
|
||||
}
|
||||
|
||||
if (!disableGCToStack) {
|
||||
builder.addExtension(llvm::PassManagerBuilder::EP_LoopOptimizerEnd,
|
||||
addGarbageCollect2StackPass);
|
||||
}
|
||||
}
|
||||
|
||||
// EP_OptimizerLast does not exist in LLVM 3.0, add it manually below.
|
||||
builder.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
|
||||
addStripExternalsPass);
|
||||
#endif
|
||||
/// LDC LICENSE END
|
||||
|
||||
builder.populateFunctionPassManager(fpm);
|
||||
builder.populateModulePassManager(mpm);
|
||||
}
|
||||
|
@ -92,7 +192,7 @@ void setupPasses(llvm::TargetMachine &targetMachine,
|
|||
fpm.add(llvm::createTargetTransformInfoWrapperPass(
|
||||
targetMachine.getTargetIRAnalysis()));
|
||||
|
||||
if (/*stripDebug*/ true) {
|
||||
if (stripDebug) {
|
||||
mpm.add(llvm::createStripSymbolsPass(true));
|
||||
}
|
||||
mpm.add(llvm::createStripDeadPrototypesPass());
|
||||
|
|
57
runtime/jit-rt/cpp-so/options.cpp
Normal file
57
runtime/jit-rt/cpp-so/options.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
//===-- options.cpp -------------------------------------------------------===//
|
||||
//
|
||||
// LDC – the LLVM D compiler
|
||||
//
|
||||
// This file is distributed under the Boost Software License. See the LICENSE
|
||||
// file for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#include "callback_ostream.h"
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
bool parseOptions(Slice<Slice<const char>> args,
|
||||
void (*errs)(void *, const char *, size_t),
|
||||
void *errsContext) {
|
||||
llvm::SmallVector<std::string, 32 - 1> tempStrs;
|
||||
tempStrs.reserve(args.len);
|
||||
llvm::SmallVector<const char *, 32> tempOpts;
|
||||
tempOpts.reserve(args.len + 1);
|
||||
tempOpts.push_back("jit"); // dummy app name
|
||||
for (size_t i = 0; i < args.len; ++i) {
|
||||
auto &arg = args.data[i];
|
||||
tempStrs.push_back(std::string(arg.data, arg.len));
|
||||
tempOpts.push_back(tempStrs.back().c_str());
|
||||
}
|
||||
|
||||
auto callback = [&](const char *str, size_t len) {
|
||||
if (errs != nullptr) {
|
||||
errs(errsContext, str, len);
|
||||
}
|
||||
};
|
||||
CallbackOstream os(callback);
|
||||
|
||||
// There is no Option::setDefault() before llvm 60
|
||||
#if LDC_LLVM_VER >= 600
|
||||
llvm::cl::ResetAllOptionOccurrences();
|
||||
for (auto &i : llvm::cl::getRegisteredOptions()) {
|
||||
i.second->setDefault();
|
||||
}
|
||||
#else
|
||||
static bool changed = false;
|
||||
if (changed) {
|
||||
os << "Cannot set options more than once";
|
||||
os.flush();
|
||||
return false;
|
||||
}
|
||||
changed = true;
|
||||
#endif
|
||||
auto res = llvm::cl::ParseCommandLineOptions(
|
||||
static_cast<int>(tempOpts.size()), tempOpts.data(), "", &os);
|
||||
os.flush();
|
||||
return res;
|
||||
}
|
23
runtime/jit-rt/cpp-so/options.h
Normal file
23
runtime/jit-rt/cpp-so/options.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
//===-- options.h - jit support ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// LDC – the LLVM D compiler
|
||||
//
|
||||
// This file is distributed under the Boost Software License. See the LICENSE
|
||||
// file for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Jit runtime - compilation options.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef OPTIONS_HPP
|
||||
#define OPTIONS_HPP
|
||||
|
||||
#include "slice.h"
|
||||
|
||||
bool parseOptions(Slice<Slice<const char>> args,
|
||||
void (*errs)(void *, const char *, size_t),
|
||||
void *errsContext);
|
||||
|
||||
#endif // OPTIONS_HPP
|
24
runtime/jit-rt/cpp-so/slice.h
Normal file
24
runtime/jit-rt/cpp-so/slice.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
//===-- slice.h - jit support -----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// LDC – the LLVM D compiler
|
||||
//
|
||||
// This file is distributed under the Boost Software License. See the LICENSE
|
||||
// file for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Jit runtime - simple memory slice class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SLICE_HPP
|
||||
#define SLICE_HPP
|
||||
|
||||
#include <cstddef> //size_t
|
||||
|
||||
template <typename T> struct Slice final {
|
||||
size_t len;
|
||||
T *data;
|
||||
};
|
||||
|
||||
#endif // SLICE_HPP
|
|
@ -20,9 +20,14 @@ struct ParamSlice;
|
|||
#ifdef _WIN32
|
||||
#define EXTERNAL __declspec(dllimport) extern
|
||||
#else
|
||||
#define EXTERNAL extern
|
||||
#define EXTERNAL __attribute__((visibility("default"))) extern
|
||||
#endif
|
||||
|
||||
template <typename T> struct Slice final {
|
||||
size_t len;
|
||||
T *data;
|
||||
};
|
||||
|
||||
#define MAKE_JIT_API_CALL_IMPL(prefix, version) prefix##version
|
||||
#define MAKE_JIT_API_CALL(prefix, version) \
|
||||
MAKE_JIT_API_CALL_IMPL(prefix, version)
|
||||
|
@ -33,6 +38,8 @@ struct ParamSlice;
|
|||
#define JIT_UNREG_BIND_PAYLOAD \
|
||||
MAKE_JIT_API_CALL(unregisterBindPayloadImplSo, \
|
||||
LDC_DYNAMIC_COMPILE_API_VERSION)
|
||||
#define JIT_SET_OPTS \
|
||||
MAKE_JIT_API_CALL(setDynamicCompilerOptsImpl, LDC_DYNAMIC_COMPILE_API_VERSION)
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
@ -50,6 +57,10 @@ EXTERNAL void JIT_REG_BIND_PAYLOAD(void *handle, void *originalFunc,
|
|||
|
||||
EXTERNAL void JIT_UNREG_BIND_PAYLOAD(void *handle);
|
||||
|
||||
EXTERNAL bool JIT_SET_OPTS(const Slice<Slice<const char>> *args,
|
||||
void (*errs)(void *, const char *, size_t),
|
||||
void *errsContext);
|
||||
|
||||
void rtCompileProcessImpl(const Context *context, std::size_t contextSize) {
|
||||
JIT_API_ENTRYPOINT(dynamiccompile_modules_head, context, contextSize);
|
||||
}
|
||||
|
@ -60,4 +71,10 @@ void registerBindPayload(void *handle, void *originalFunc,
|
|||
}
|
||||
|
||||
void unregisterBindPayload(void *handle) { JIT_UNREG_BIND_PAYLOAD(handle); }
|
||||
|
||||
bool setDynamicCompilerOpts(const Slice<Slice<const char>> *args,
|
||||
void (*errs)(void *, const char *, size_t),
|
||||
void *errsContext) {
|
||||
return JIT_SET_OPTS(args, errs, errsContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,6 +252,32 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/+
|
||||
+ Set options for dynamic compiler.
|
||||
+ Returns false on error.
|
||||
+
|
||||
+ This function is not thread-safe.
|
||||
+
|
||||
+ Example:
|
||||
+ ---
|
||||
+ import ldc.attributes, ldc.dynamic_compile;
|
||||
+
|
||||
+ auto res = setDynamicCompilerOptions(["-disable-gc2stack"]);
|
||||
+ assert(res);
|
||||
+
|
||||
+ res = setDynamicCompilerOptions(["-invalid_option"], (in char[] str)
|
||||
+ {
|
||||
+ writeln("Error: ", str);
|
||||
+ });
|
||||
+ assert(!res);
|
||||
+/
|
||||
bool setDynamicCompilerOptions(string[] args, scope ErrsHandler errs = null)
|
||||
{
|
||||
auto errsFunc = (errs !is null ? &errsWrapper : null);
|
||||
auto errsFuncContext = (errs !is null ? cast(void*)&errs : null);
|
||||
return setDynamicCompilerOpts(&args, errsFunc, errsFuncContext);
|
||||
}
|
||||
|
||||
private:
|
||||
auto bindImpl(F, Args...)(F func, Args args)
|
||||
{
|
||||
|
@ -436,6 +462,8 @@ struct BindPayload(OF, F, int[] Index, Args...)
|
|||
alias toDelegate = base.toDelegate;
|
||||
}
|
||||
|
||||
alias ErrsHandler = void delegate(const(char)[]);
|
||||
|
||||
extern(C)
|
||||
{
|
||||
enum ParamType : uint {
|
||||
|
@ -465,6 +493,13 @@ void dumpHandlerWrapper(void* context, DumpStage stage, const char* buff, size_t
|
|||
(*del)(stage, buff[0..len]);
|
||||
}
|
||||
|
||||
void errsWrapper(void* context, const char* str, size_t len)
|
||||
{
|
||||
alias DelType = ErrsHandler;
|
||||
auto del = cast(DelType*)context;
|
||||
assert(str !is null);
|
||||
(*del)(str[0..len]);
|
||||
}
|
||||
|
||||
// must be synchronized with cpp
|
||||
struct Context
|
||||
|
@ -480,7 +515,8 @@ struct Context
|
|||
}
|
||||
extern void rtCompileProcessImpl(const ref Context context, size_t contextSize);
|
||||
|
||||
void registerBindPayload(void* handle, void* originalFunc, void* exampleFunc, const ParamSlice* params, size_t paramsSize);
|
||||
void unregisterBindPayload(void* handle);
|
||||
extern void registerBindPayload(void* handle, void* originalFunc, void* exampleFunc, const ParamSlice* params, size_t paramsSize);
|
||||
extern void unregisterBindPayload(void* handle);
|
||||
extern bool setDynamicCompilerOpts(const(string[])* args, void function(void*, const char*, size_t) errs, void* errsContext);
|
||||
}
|
||||
|
||||
|
|
52
tests/dynamiccompile/options.d
Normal file
52
tests/dynamiccompile/options.d
Normal file
|
@ -0,0 +1,52 @@
|
|||
|
||||
// RUN: %ldc -enable-dynamic-compile -run %s
|
||||
|
||||
import std.stdio;
|
||||
import std.array;
|
||||
import std.string;
|
||||
import ldc.attributes;
|
||||
import ldc.dynamic_compile;
|
||||
|
||||
@dynamicCompile int foo()
|
||||
{
|
||||
int* i = new int;
|
||||
*i = 42;
|
||||
return *i;
|
||||
}
|
||||
|
||||
void main(string[] args)
|
||||
{
|
||||
foreach (bool add_opt; [false, true])
|
||||
{
|
||||
auto dump = appender!string();
|
||||
CompilerSettings settings;
|
||||
settings.optLevel = 3;
|
||||
settings.dumpHandler = (DumpStage stage, in char[] str)
|
||||
{
|
||||
if (DumpStage.OptimizedModule == stage)
|
||||
{
|
||||
write(str);
|
||||
dump.put(str);
|
||||
}
|
||||
};
|
||||
writeln("===========================================");
|
||||
if (add_opt)
|
||||
{
|
||||
auto res = setDynamicCompilerOptions(["-disable-gc2stack"]);
|
||||
assert(res);
|
||||
}
|
||||
compileDynamicCode(settings);
|
||||
writeln();
|
||||
writeln("===========================================");
|
||||
stdout.flush();
|
||||
|
||||
if (add_opt)
|
||||
{
|
||||
assert(count(dump.data, "_d_allocmemoryT") > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(count(dump.data, "_d_allocmemoryT") == 0);
|
||||
}
|
||||
}
|
||||
}
|
23
tests/dynamiccompile/options_invalid.d
Normal file
23
tests/dynamiccompile/options_invalid.d
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
// RUN: %ldc -enable-dynamic-compile -run %s
|
||||
|
||||
import std.array;
|
||||
import std.string;
|
||||
import ldc.attributes;
|
||||
import ldc.dynamic_compile;
|
||||
|
||||
@dynamicCompile int foo()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
void main(string[] args)
|
||||
{
|
||||
auto dump = appender!string();
|
||||
auto res = setDynamicCompilerOptions(["-invalid_option"], (in char[] str)
|
||||
{
|
||||
dump.put(str);
|
||||
});
|
||||
assert(!res);
|
||||
assert(dump.data.length > 0);
|
||||
}
|
58
tests/dynamiccompile/options_multiple_changes.d
Normal file
58
tests/dynamiccompile/options_multiple_changes.d
Normal file
|
@ -0,0 +1,58 @@
|
|||
|
||||
// RUN: %ldc -enable-dynamic-compile -run %s
|
||||
// REQUIRES: atleast_llvm600
|
||||
|
||||
import std.stdio;
|
||||
import std.array;
|
||||
import std.string;
|
||||
import ldc.attributes;
|
||||
import ldc.dynamic_compile;
|
||||
|
||||
@dynamicCompile int foo()
|
||||
{
|
||||
int* i = new int;
|
||||
*i = 42;
|
||||
return *i;
|
||||
}
|
||||
|
||||
void main(string[] args)
|
||||
{
|
||||
foreach (bool add_opt; [false, true, false, true, false])
|
||||
{
|
||||
auto dump = appender!string();
|
||||
CompilerSettings settings;
|
||||
settings.optLevel = 3;
|
||||
settings.dumpHandler = (DumpStage stage, in char[] str)
|
||||
{
|
||||
if (DumpStage.OptimizedModule == stage)
|
||||
{
|
||||
write(str);
|
||||
dump.put(str);
|
||||
}
|
||||
};
|
||||
writeln("===========================================");
|
||||
if (add_opt)
|
||||
{
|
||||
auto res = setDynamicCompilerOptions(["-disable-gc2stack"]);
|
||||
assert(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto res = setDynamicCompilerOptions([]);
|
||||
assert(res);
|
||||
}
|
||||
compileDynamicCode(settings);
|
||||
writeln();
|
||||
writeln("===========================================");
|
||||
stdout.flush();
|
||||
|
||||
if (add_opt)
|
||||
{
|
||||
assert(count(dump.data, "_d_allocmemoryT") > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(count(dump.data, "_d_allocmemoryT") == 0);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue