Make LDC custom passes available to jit, add API for jit compiler options (#2758)

This commit is contained in:
Ivan Butygin 2019-09-08 09:16:05 +03:00 committed by GitHub
parent b6d8210255
commit a40c6c7fd2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 478 additions and 27 deletions

View file

@ -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))

View file

@ -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

View file

@ -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"

View file

@ -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"

View file

@ -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;
}

View file

@ -13,8 +13,6 @@
#pragma once
#include "gen/metadata.h"
namespace llvm {
class FunctionPass;
class ModulePass;

View file

@ -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;

View file

@ -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"

View file

@ -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"

View file

@ -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 "")

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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());

View 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;
}

View 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

View 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

View file

@ -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);
}
}

View file

@ -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);
}

View 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);
}
}
}

View 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);
}

View 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);
}
}
}