Merge branch 'master' into merge-2.078

This commit is contained in:
Martin 2018-01-26 18:52:49 +01:00
commit 1b860e70d7
45 changed files with 579 additions and 200 deletions

View file

@ -388,6 +388,7 @@ if(LDC_DYNAMIC_COMPILE STREQUAL "AUTO")
set(LDC_DYNAMIC_COMPILE True)
message(STATUS "Building LDC with dynamic compilation support")
add_definitions(-DLDC_DYNAMIC_COMPILE)
add_definitions(-DLDC_DYNAMIC_COMPILE_API_VERSION=1)
endif()
endif()
@ -745,9 +746,7 @@ else()
endif()
set(LDC_INSTALL_LLVM_RUNTIME_LIBS ${LDC_INSTALL_LLVM_RUNTIME_LIBS_DEFAULT} CACHE BOOL "Copy/install runtime libraries (ASan, libFuzzer) from LLVM/Clang into LDC lib dir when available.")
function(copy_compilerrt_lib llvm_lib_name ldc_lib_name fixup_dylib)
# The LLVM version string can contain the SVN revision number, so cut that off
string(SUBSTRING "${LLVM_VERSION_STRING}" 0 5 LLVM_VERSION_STRING_CROPPED)
set(llvm_lib_path ${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_STRING_CROPPED}/lib/${llvm_lib_name})
set(llvm_lib_path ${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_BASE_STRING}/lib/${llvm_lib_name})
if(EXISTS ${llvm_lib_path})
message(STATUS "Copying runtime library: ${llvm_lib_path} --> ${ldc_lib_name}")
set(ldc_lib_path ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/${ldc_lib_name})
@ -768,9 +767,13 @@ if (LDC_INSTALL_LLVM_RUNTIME_LIBS)
copy_compilerrt_lib("darwin/libclang_rt.asan_osx_dynamic.dylib" "libldc_rt.asan_osx_dynamic.dylib" TRUE)
if(NOT (LDC_LLVM_VER LESS 600))
copy_compilerrt_lib("darwin/libclang_rt.fuzzer_osx.a" "libldc_rt.fuzzer_osx.a" FALSE)
copy_compilerrt_lib("darwin/libclang_rt.xray_osx.a" "libldc_rt.xray_osx.a" FALSE)
endif()
elseif(UNIX)
copy_compilerrt_lib("linux/libclang_rt.asan-x86_64.a" "libldc_rt.asan-x86_64.a" FALSE)
if(NOT (LDC_LLVM_VER LESS 500))
copy_compilerrt_lib("linux/libclang_rt.xray-x86_64.a" "libldc_rt.xray-x86_64.a" FALSE)
endif()
if(NOT (LDC_LLVM_VER LESS 600))
copy_compilerrt_lib("linux/libclang_rt.fuzzer-x86_64.a" "libldc_rt.fuzzer-x86_64.a" FALSE)
endif()

View file

@ -17,7 +17,8 @@
# llvm-config is searched for in ${LLVM_ROOT_DIR}/bin.
# LLVM_VERSION_MAJOR - Major version of LLVM.
# LLVM_VERSION_MINOR - Minor version of LLVM.
# LLVM_VERSION_STRING - Full LLVM version string (e.g. 2.9).
# LLVM_VERSION_STRING - Full LLVM version string (e.g. 6.0.0svn).
# LLVM_VERSION_BASE_STRING - Base LLVM version string without git/svn suffix (e.g. 6.0.0).
#
# Note: The variable names were chosen in conformance with the offical CMake
# guidelines, see ${CMAKE_ROOT}/Modules/readme.txt.
@ -105,6 +106,9 @@ else()
llvm_set(ROOT_DIR prefix true)
llvm_set(ENABLE_ASSERTIONS assertion-mode)
# The LLVM version string _may_ contain a git/svn suffix, so cut that off
string(SUBSTRING "${LLVM_VERSION_STRING}" 0 5 LLVM_VERSION_BASE_STRING)
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-8][\\.0-9A-Za-z]*")
# Versions below 3.9 do not support components debuginfocodeview, globalisel
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfocodeview" index)

View file

@ -1012,6 +1012,11 @@ extern (C++) class VarDeclaration : Declaration
Expression edtor; // if !=null, does the destruction of the variable
IntRange* range; // if !=null, the variable is known to be within the range
version (IN_LLVM)
{
TypeClass scopeClassType; // real (dynamic) type if onstack == true (stack-allocated class)
}
final extern (D) this(Loc loc, Type type, Identifier id, Initializer _init, StorageClass storage_class = STCundefined)
{
super(id);

View file

@ -267,6 +267,10 @@ public:
Expression *edtor; // if !=NULL, does the destruction of the variable
IntRange *range; // if !NULL, the variable is known to be within the range
#if IN_LLVM
TypeClass *scopeClassType; // real (dynamic) type if onstack == true (stack-allocated class)
#endif
Dsymbol *syntaxCopy(Dsymbol *);
void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
const char *kind() const;

View file

@ -2585,6 +2585,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
ne.onstack = 1;
dsym.onstack = true;
version (IN_LLVM)
{
dsym.scopeClassType = cast(TypeClass) ne.newtype;
}
}
}
}

View file

@ -17,6 +17,8 @@
#include "errors.h"
#include "globals.h"
#include "gen/to_string.h"
#include "llvm/ADT/Triple.h"
namespace {
namespace cl = llvm::cl;
@ -51,6 +53,15 @@ cl::opt<std::string> ASTPGOInstrUseFile(
cl::desc("Use instrumentation data for profile-guided optimization"),
cl::ValueRequired);
#if LDC_LLVM_VER >= 500
cl::opt<int> fXRayInstructionThreshold(
"fxray-instruction-threshold", cl::value_desc("value"),
cl::desc("Sets the minimum function size to instrument with XRay"),
cl::init(200), cl::ZeroOrMore, cl::ValueRequired);
#else
constexpr int fXRayInstructionThreshold = 200;
#endif
} // anonymous namespace
namespace opts {
@ -67,7 +78,21 @@ static cl::opt<bool> dmdFunctionTrace(
"fdmd-trace-functions", cl::ZeroOrMore,
cl::desc("DMD-style runtime performance profiling of generated code"));
void initializeInstrumentationOptionsFromCmdline() {
#if LDC_LLVM_VER >= 500
cl::opt<bool> fXRayInstrument(
"fxray-instrument", cl::ZeroOrMore,
cl::desc("Generate XRay instrumentation sleds on function entry and exit"));
#endif
llvm::StringRef getXRayInstructionThresholdString() {
// The instruction threshold is constant during one compiler invoke, so we
// can cache the int->string conversion result.
static std::string thresholdString =
ldc::to_string(fXRayInstructionThreshold);
return thresholdString;
}
void initializeInstrumentationOptionsFromCmdline(const llvm::Triple &triple) {
if (ASTPGOInstrGenFile.getNumOccurrences() > 0) {
pgoMode = PGO_ASTBasedInstr;
if (ASTPGOInstrGenFile.empty()) {
@ -101,9 +126,7 @@ void initializeInstrumentationOptionsFromCmdline() {
// There is a bug in (our use of?) LLVM where codegen errors with
// PGO_IRBasedInstr for Windows targets. So disable IRBased PGO on Windows for
// now.
assert(global.params.targetTriple);
if ((pgoMode == PGO_IRBasedInstr) &&
global.params.targetTriple->isOSWindows()) {
if ((pgoMode == PGO_IRBasedInstr) && triple.isOSWindows()) {
error(Loc(),
"'-fprofile-generate' is not yet supported for Windows targets.");
}

View file

@ -18,15 +18,26 @@
#include "gen/cl_helpers.h"
namespace llvm {
class Triple;
}
namespace opts {
namespace cl = llvm::cl;
extern cl::opt<bool> instrumentFunctions;
#if LDC_LLVM_VER >= 500
extern cl::opt<bool> fXRayInstrument;
#else
constexpr bool fXRayInstrument = false;
#endif
llvm::StringRef getXRayInstructionThresholdString();
/// This initializes the instrumentation options, and checks the validity of the
/// commandline flags. targetTriple should be initialized before calling this.
/// It should be called only once.
void initializeInstrumentationOptionsFromCmdline();
void initializeInstrumentationOptionsFromCmdline(const llvm::Triple &triple);
enum PGOKind {
PGO_None,

View file

@ -14,6 +14,7 @@ namespace ldc {
const char * const ldc_version = "@LDC_VERSION@";
const char * const dmd_version = "v@DMD_VERSION@";
const char * const llvm_version = "@LLVM_VERSION_STRING@";
const char * const llvm_version_base = "@LLVM_VERSION_BASE_STRING@";
const char * const built_with_Dcompiler_version = "@D_COMPILER_VERSION_STRING@";
}

View file

@ -15,6 +15,7 @@ namespace ldc {
extern const char *const ldc_version;
extern const char *const dmd_version;
extern const char *const llvm_version;
extern const char *const llvm_version_base; /// the base LLVM version without svn/git suffix
extern const char *const built_with_Dcompiler_version;
}

View file

@ -12,6 +12,7 @@
#include "driver/cl_options_instrumentation.h"
#include "driver/cl_options_sanitizers.h"
#include "driver/exe_path.h"
#include "driver/ldc-version.h"
#include "driver/tool.h"
#include "gen/irstate.h"
#include "gen/logger.h"
@ -52,6 +53,7 @@ private:
virtual void addASanLinkFlags(const llvm::Triple &triple);
virtual void addFuzzLinkFlags(const llvm::Triple &triple);
virtual void addCppStdlibLinkFlags(const llvm::Triple &triple);
virtual void addXRayLinkFlags(const llvm::Triple &triple);
virtual void addLinker();
virtual void addUserSwitches();
@ -205,6 +207,36 @@ std::string getFullCompilerRTLibPath(const llvm::Triple &triple,
}
}
// Clang's RT libs are in a subdir of the lib dir.
// Returns the libname as full path and with arch suffix and extension.
// For example, with name="libclang_rt.asan" and sharedLibrary=true, the
// returned string is
// "clang/6.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib" on Darwin.
// This function is "best effort", the path may not be what Clang does...
// See clang/lib/Driver/Toolchain.cpp.
std::string getFullClangCompilerRTLibPath(const llvm::Triple &triple,
llvm::StringRef name,
bool sharedLibrary = false) {
llvm::StringRef OSName =
triple.isOSDarwin()
? "darwin"
: triple.isOSFreeBSD() ? "freebsd" : triple.getOSName();
std::string relPath = (llvm::Twine("clang/") + ldc::llvm_version_base +
"/lib/" + OSName + "/" + name)
.str();
if (triple.isOSDarwin()) {
return exe_path::prependLibDir(
llvm::Twine(relPath) +
(sharedLibrary ? "_osx_dynamic.dylib" : "_osx.a"));
} else {
return exe_path::prependLibDir(llvm::Twine(relPath) + "-" +
getCompilerRTArchName(triple) +
(sharedLibrary ? ".so" : ".a"));
}
}
void ArgsBuilder::addASanLinkFlags(const llvm::Triple &triple) {
// Examples: "libclang_rt.asan-x86_64.a" or "libclang_rt.asan-arm.a" and
// "libclang_rt.asan-x86_64.so"
@ -217,12 +249,14 @@ void ArgsBuilder::addASanLinkFlags(const llvm::Triple &triple) {
std::string searchPaths[] = {
getFullCompilerRTLibPath(triple, "libldc_rt.asan", linkSharedASan),
getFullCompilerRTLibPath(triple, "libclang_rt.asan", linkSharedASan),
getFullClangCompilerRTLibPath(triple, "libclang_rt.asan", linkSharedASan),
};
for (const auto &filepath : searchPaths) {
IF_LOG Logger::println("Searching ASan lib: %s", filepath.c_str());
if (llvm::sys::fs::exists(filepath)) {
if (llvm::sys::fs::exists(filepath) &&
!llvm::sys::fs::is_directory(filepath)) {
IF_LOG Logger::println("Found, linking with %s", filepath.c_str());
args.push_back(filepath);
@ -256,6 +290,7 @@ void ArgsBuilder::addFuzzLinkFlags(const llvm::Triple &triple) {
#if LDC_LLVM_VER >= 600
getFullCompilerRTLibPath(triple, "libldc_rt.fuzzer"),
getFullCompilerRTLibPath(triple, "libclang_rt.fuzzer"),
getFullClangCompilerRTLibPath(triple, "libclang_rt.fuzzer"),
#else
exe_path::prependLibDir("libFuzzer.a"),
exe_path::prependLibDir("libLLVMFuzzer.a"),
@ -265,7 +300,8 @@ void ArgsBuilder::addFuzzLinkFlags(const llvm::Triple &triple) {
for (const auto &filepath : searchPaths) {
IF_LOG Logger::println("Searching libFuzzer: %s", filepath.c_str());
if (llvm::sys::fs::exists(filepath)) {
if (llvm::sys::fs::exists(filepath) &&
!llvm::sys::fs::is_directory(filepath)) {
IF_LOG Logger::println("Found, linking with %s", filepath.c_str());
args.push_back(filepath);
@ -277,6 +313,32 @@ void ArgsBuilder::addFuzzLinkFlags(const llvm::Triple &triple) {
}
}
// Adds all required link flags for -fxray-instrument when the xray library is
// found.
void ArgsBuilder::addXRayLinkFlags(const llvm::Triple &triple) {
std::string searchPaths[] = {
getFullCompilerRTLibPath(triple, "libldc_rt.xray"),
getFullCompilerRTLibPath(triple, "libclang_rt.xray"),
getFullClangCompilerRTLibPath(triple, "libclang_rt.xray"),
};
bool linkerDarwin = triple.isOSDarwin();
if (!triple.isOSLinux())
warning(Loc(), "XRay is not (fully) supported on non-Linux target OS.");
for (const auto &filepath : searchPaths) {
if (!linkerDarwin)
addLdFlag("--whole-archive");
args.push_back(filepath);
if (!linkerDarwin)
addLdFlag("--no-whole-archive");
return;
}
}
void ArgsBuilder::addCppStdlibLinkFlags(const llvm::Triple &triple) {
if (linkNoCpp)
return;
@ -375,6 +437,10 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
addSanitizers(*global.params.targetTriple);
if (opts::fXRayInstrument) {
addXRayLinkFlags(*global.params.targetTriple);
}
#if LDC_LLVM_VER >= 309
// Add LTO link flags before adding the user link switches, such that the user
// can pass additional options to the LTO plugin.

View file

@ -1064,7 +1064,8 @@ int cppmain(int argc, char **argv) {
global.lib_ext = "a";
}
opts::initializeInstrumentationOptionsFromCmdline();
opts::initializeInstrumentationOptionsFromCmdline(
*global.params.targetTriple);
Strings libmodules;
return mars_mainBody(files, libmodules);

View file

@ -146,7 +146,11 @@ class AssemblyAnnotator : public AssemblyAnnotationWriter {
return "";
}
const llvm::DataLayout &DL;
public:
AssemblyAnnotator(const llvm::DataLayout &dl) : DL{dl} {}
void emitFunctionAnnot(const Function *F,
formatted_raw_ostream &os) override {
os << "; [#uses = " << F->getNumUses() << ']';
@ -172,7 +176,7 @@ public:
os << ", type = " << *val.getType();
} else if (isa<AllocaInst>(&val)) {
os << ", size/byte = "
<< gDataLayout->getTypeAllocSize(val.getType()->getContainedType(0));
<< DL.getTypeAllocSize(val.getType()->getContainedType(0));
}
os << ']';
}
@ -387,7 +391,7 @@ void writeModule(llvm::Module *m, const char *filename) {
errinfo.message().c_str());
fatal();
}
AssemblyAnnotator annotator;
AssemblyAnnotator annotator(m->getDataLayout());
m->print(aos, &annotator);
}

View file

@ -84,7 +84,7 @@ struct LLTypeMemoryLayout {
/// Removes padding fields for (non-union-containing!) structs
struct RemoveStructPadding : ABIRewrite {
LLValue *put(DValue *v) override {
LLValue *put(DValue *v, bool) override {
return DtoUnpaddedStruct(v->type->toBasetype(), DtoLVal(v));
}
@ -155,7 +155,7 @@ struct IntegerRewrite : ABIRewrite {
return LLTypeMemoryLayout::typesAreEquivalent(llType, integerType);
}
LLValue *put(DValue *dv) override {
LLValue *put(DValue *dv, bool) override {
LLValue *address = getAddressOf(dv);
LLType *integerType = getIntegerType(dv->type->size());
return loadFromMemory(address, integerType);
@ -189,20 +189,8 @@ struct ExplicitByvalRewrite : ABIRewrite {
explicit ExplicitByvalRewrite(unsigned minAlignment = 16)
: minAlignment(minAlignment) {}
LLValue *put(DValue *v) override {
const unsigned align = alignment(v->type);
if (!DtoIsInMemoryOnly(v->type)) {
return DtoAllocaDump(DtoRVal(v), align,
".ExplicitByvalRewrite_dump");
}
LLValue *originalPointer = DtoLVal(v);
LLType *type = originalPointer->getType()->getPointerElementType();
LLValue *copyForCallee =
DtoRawAlloca(type, align, ".ExplicitByvalRewrite_dump");
DtoMemCpy(copyForCallee, originalPointer);
return copyForCallee;
LLValue *put(DValue *v, bool) override {
return DtoAllocaDump(v, alignment(v->type), ".ExplicitByvalRewrite_dump");
}
LLValue *getLVal(Type *dty, LLValue *v) override {
@ -225,7 +213,7 @@ struct HFAToArray : ABIRewrite {
HFAToArray(const int max = 4) : maxFloats(max) {}
LLValue *put(DValue *dv) override {
LLValue *put(DValue *dv, bool) override {
Logger::println("rewriting HFA %s -> as array", dv->type->toChars());
LLType *t = type(dv->type);
return DtoLoad(DtoBitCast(DtoLVal(dv), getPtrToType(t)));
@ -249,7 +237,7 @@ struct HFAToArray : ABIRewrite {
* Rewrite a composite as array of i64.
*/
struct CompositeToArray64 : ABIRewrite {
LLValue *put(DValue *dv) override {
LLValue *put(DValue *dv, bool) override {
Logger::println("rewriting %s -> as i64 array", dv->type->toChars());
LLType *t = type(dv->type);
return DtoLoad(DtoBitCast(DtoLVal(dv), getPtrToType(t)));
@ -271,7 +259,7 @@ struct CompositeToArray64 : ABIRewrite {
* Rewrite a composite as array of i32.
*/
struct CompositeToArray32 : ABIRewrite {
LLValue *put(DValue *dv) override {
LLValue *put(DValue *dv, bool) override {
Logger::println("rewriting %s -> as i32 array", dv->type->toChars());
LLType *t = type(dv->type);
return DtoLoad(DtoBitCast(DtoLVal(dv), getPtrToType(t)));

View file

@ -171,7 +171,7 @@ struct RegCount {
* memory so that it's then readable as the other type (i.e., bit-casting).
*/
struct X86_64_C_struct_rewrite : ABIRewrite {
LLValue *put(DValue *v) override {
LLValue *put(DValue *v, bool) override {
LLValue *address = getAddressOf(v);
LLType *abiTy = getAbiType(v->type);
@ -196,7 +196,12 @@ struct X86_64_C_struct_rewrite : ABIRewrite {
* the ByVal LLVM attribute.
*/
struct ImplicitByvalRewrite : ABIRewrite {
LLValue *put(DValue *v) override { return getAddressOf(v); }
LLValue *put(DValue *v, bool isModifiableLvalue) override {
if (isModifiableLvalue && v->isLVal()) {
return DtoAllocaDump(v, ".lval_copy_for_ImplicitByvalRewrite");
}
return getAddressOf(v);
}
LLValue *getLVal(Type *dty, LLValue *v) override { return v; }

View file

@ -42,7 +42,7 @@ struct ABIRewrite {
virtual ~ABIRewrite() = default;
/// Transforms the D argument to a suitable LL argument.
virtual llvm::Value *put(DValue *v) = 0;
virtual llvm::Value *put(DValue *v, bool isModifiableLvalue) = 0;
/// Transforms the LL parameter back and returns the address for the D
/// parameter.

View file

@ -21,6 +21,7 @@
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/nested.h"
#include "gen/optimizer.h"
#include "gen/rttibuilder.h"
#include "gen/runtime.h"
#include "gen/structs.h"
@ -193,6 +194,50 @@ void DtoFinalizeClass(Loc &loc, LLValue *inst) {
////////////////////////////////////////////////////////////////////////////////
void DtoFinalizeScopeClass(Loc &loc, LLValue *inst, ClassDeclaration *cd) {
if (!isOptimizationEnabled()) {
DtoFinalizeClass(loc, inst);
return;
}
assert(cd);
// As of 2.077, the front-end doesn't emit the implicit delete() for C++
// classes, so this code assumes D classes.
assert(!cd->isCPPclass());
bool hasDtor = false;
for (; cd; cd = cd->baseClass) {
if (cd->dtor) {
hasDtor = true;
break;
}
}
if (hasDtor) {
DtoFinalizeClass(loc, inst);
return;
}
// no dtors => only finalize (via druntime call) if monitor is set,
// see https://github.com/ldc-developers/ldc/issues/2515
llvm::BasicBlock *ifbb = gIR->insertBB("if");
llvm::BasicBlock *endbb = gIR->insertBBAfter(ifbb, "endif");
const auto monitor = DtoLoad(DtoGEPi(inst, 0, 1), ".monitor");
const auto hasMonitor =
gIR->ir->CreateICmp(llvm::CmpInst::ICMP_NE, monitor,
getNullValue(monitor->getType()), ".hasMonitor");
llvm::BranchInst::Create(ifbb, endbb, hasMonitor, gIR->scopebb());
gIR->scope() = IRScope(ifbb);
DtoFinalizeClass(loc, inst);
gIR->ir->CreateBr(endbb);
gIR->scope() = IRScope(endbb);
}
////////////////////////////////////////////////////////////////////////////////
DValue *DtoCastClass(Loc &loc, DValue *val, Type *_to) {
IF_LOG Logger::println("DtoCastClass(%s, %s)", val->type->toChars(),
_to->toChars());

View file

@ -33,6 +33,7 @@ llvm::Constant *DtoDefineClassInfo(ClassDeclaration *cd);
DValue *DtoNewClass(Loc &loc, TypeClass *type, NewExp *newexp);
void DtoInitClass(TypeClass *tc, llvm::Value *dst);
void DtoFinalizeClass(Loc &loc, llvm::Value *inst);
void DtoFinalizeScopeClass(Loc &loc, llvm::Value *inst, ClassDeclaration *cd);
DValue *DtoCastClass(Loc &loc, DValue *val, Type *to);
DValue *DtoDynamicCastObject(Loc &loc, DValue *val, Type *to);

View file

@ -31,7 +31,7 @@ struct DComputePointerRewrite : ABIRewrite {
// TODO: Is this correct?
return DtoAllocaDump(v, this->type(dty));
}
LLValue *put(DValue *dv) override {
LLValue *put(DValue *dv, bool) override {
LLValue *address = getAddressOf(dv);
LLType *t = this->type(dv->type);
return loadFromMemory(address, t);

View file

@ -36,9 +36,10 @@ void DComputeTarget::doCodeGen(Module *m) {
void DComputeTarget::emit(Module *m) {
// Reset the global ABI to the target's ABI. Necessary because we have
// multiple ABI we are trying to target. Also reset gIR. These are both
// reused. Somewhat of a HACK.
// reused. MAJOR HACK.
gABI = abi;
gIR = _ir;
gTargetMachine = targetMachine;
doCodeGen(m);
}
@ -52,7 +53,6 @@ void DComputeTarget::writeModule() {
const char *path = FileName::combine(global.params.objdir, os.str().c_str());
setGTargetMachine();
::writeModule(&_ir->module, path);
delete _ir;

View file

@ -18,6 +18,7 @@
namespace llvm {
class Module;
class Function;
class TargetMachine;
}
class Module;
@ -32,6 +33,7 @@ public:
const char *short_name;
const char *binSuffix;
TargetABI *abi;
llvm::TargetMachine *targetMachine = nullptr;
// The nominal address spaces in DCompute are Private = 0, Global = 1,
// Shared = 2, Constant = 3, Generic = 4
std::array<int, 5> mapping;
@ -47,8 +49,6 @@ public:
void doCodeGen(Module *m);
void writeModule();
// HACK: Resets the gTargetMachine to one appropriate for this dcompute target
virtual void setGTargetMachine() = 0;
virtual void addMetadata() = 0;
virtual void addKernelMetadata(FuncDeclaration *df, llvm::Function *llf) = 0;
};

View file

@ -16,6 +16,7 @@
#include "gen/logger.h"
#include "gen/optimizer.h"
#include "gen/to_string.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include "driver/targetmachine.h"
#include <cstring>
@ -30,35 +31,25 @@ public:
// Map from nominal DCompute address space to NVPTX address space.
// see $LLVM_ROOT/docs/docs/NVPTXUsage.rst section Address Spaces
{{5, 1, 3, 4, 0}}) {
std::string dl =
global.params.is64bit
? "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:"
"32-"
"f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
: "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:"
"32-"
"f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64";
const bool is64 = global.params.is64bit;
auto tripleString = is64 ? "nvptx64-nvidia-cuda" : "nvptx-nvidia-cuda";
targetMachine = createTargetMachine(
tripleString, is64 ? "nvptx64" : "nvptx",
"sm_" + ldc::to_string(tversion / 10), {},
is64 ? ExplicitBitness::M64 : ExplicitBitness::M32, ::FloatABI::Hard,
llvm::Reloc::Static, llvm::CodeModel::Medium, codeGenOptLevel(), false);
_ir = new IRState("dcomputeTargetCUDA", ctx);
_ir->module.setTargetTriple(global.params.is64bit ? "nvptx64-nvidia-cuda"
: "nvptx-nvidia-cuda");
_ir->module.setDataLayout(dl);
_ir->module.setTargetTriple(tripleString);
_ir->module.setDataLayout(targetMachine->createDataLayout());
_ir->dcomputetarget = this;
}
void addMetadata() override {
// sm version?
}
void setGTargetMachine() override {
const bool is64 = global.params.is64bit;
gTargetMachine = createTargetMachine(
is64 ? "nvptx64-nvidia-cuda" : "nvptx-nvidia-cuda",
is64 ? "nvptx64" : "nvptx", "sm_" + ldc::to_string(tversion / 10), {},
is64 ? ExplicitBitness::M64 : ExplicitBitness::M32, ::FloatABI::Hard,
llvm::Reloc::Static, llvm::CodeModel::Medium, codeGenOptLevel(),
false);
}
void addKernelMetadata(FuncDeclaration *df, llvm::Function *llf) override {
// TODO: Handle Function attibutes

View file

@ -52,7 +52,6 @@ public:
: SPIR_DATALAYOUT32);
_ir->dcomputetarget = this;
}
void setGTargetMachine() override { gTargetMachine = nullptr; }
// Adapted from clang
void addMetadata() override {

View file

@ -26,6 +26,10 @@
namespace {
enum {
ApiVersion = LDC_DYNAMIC_COMPILE_API_VERSION
};
const char *DynamicCompileModulesHeadName = "dynamiccompile_modules_head";
llvm::GlobalValue *getPredefinedSymbol(llvm::Module &module,
@ -458,6 +462,7 @@ llvm::StructType *getFuncListElemType(llvm::LLVMContext &context) {
// struct RtCompileModuleList
// {
// i32 version; // Must be first
// RtCompileModuleList* next;
// i8* irData;
// i32 irDataSize;
@ -477,6 +482,7 @@ llvm::StructType *getModuleListElemType(llvm::LLVMContext &context,
llvm::StructType *ret =
llvm::StructType::create(context /*, "RtCompileModuleList"*/); // fwddecl
llvm::Type *elements[] = {
llvm::IntegerType::get(context, 32),
llvm::PointerType::getUnqual(ret),
llvm::IntegerType::getInt8PtrTy(context),
llvm::IntegerType::get(context, 32),
@ -579,8 +585,10 @@ llvm::GlobalVariable *generateModuleListElem(IRState *irs, const Types &types,
auto symListInit = generateSymList(irs, types, globalVals);
auto varlistInit = generateVarList(irs, types);
llvm::Constant *fields[] = {
llvm::ConstantInt::get(irs->context(),
APInt(32, ApiVersion)), // version
llvm::ConstantPointerNull::get(llvm::dyn_cast<llvm::PointerType>(
elem_type->getElementType(0))), // next
elem_type->getElementType(1))), // next
irData->getInitializer(), // irdata
irDataLen->getInitializer(), // irdata len
funcListInit.first, // funclist
@ -633,9 +641,9 @@ void generateCtorBody(IRState *irs, const Types &types, llvm::Function *func,
builder.SetInsertPoint(bb);
auto zero64 = llvm::ConstantInt::get(irs->context(), APInt(64, 0));
auto zero32 = llvm::ConstantInt::get(irs->context(), APInt(32, 0));
auto elemIndex = llvm::ConstantInt::get(irs->context(), APInt(32, 1));
auto modListHeadPtr = declareModListHead(irs->module, types);
llvm::Value *gepVals[] = {zero64, zero32};
llvm::Value *gepVals[] = {zero64, elemIndex};
auto elemNextPtr = builder.CreateGEP(modListElem, gepVals);
auto prevHeadVal = builder.CreateLoad(builder.CreateBitOrPointerCast(
modListHeadPtr, types.modListElemType->getPointerTo()->getPointerTo()));

View file

@ -19,6 +19,7 @@
#include "statement.h"
#include "template.h"
#include "driver/cl_options.h"
#include "driver/cl_options_instrumentation.h"
#include "driver/cl_options_sanitizers.h"
#include "gen/abi.h"
#include "gen/arrays.h"
@ -463,6 +464,18 @@ void applyTargetMachineAttributes(llvm::Function &func,
willEliminateFramePointer() ? "false" : "true");
}
void applyXRayAttributes(FuncDeclaration &fdecl, llvm::Function &func) {
if (!opts::fXRayInstrument)
return;
if (!fdecl.emitInstrumentation) {
func.addFnAttr("function-instrument", "xray-never");
} else {
func.addFnAttr("xray-instruction-threshold",
opts::getXRayInstructionThresholdString());
}
}
} // anonymous namespace
////////////////////////////////////////////////////////////////////////////////
@ -1010,6 +1023,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
func->addFnAttr(LLAttribute::SanitizeThread);
}
}
applyXRayAttributes(*fd, *func);
llvm::BasicBlock *beginbb =
llvm::BasicBlock::Create(gIR->context(), "", func);

View file

@ -219,12 +219,30 @@ LLValue *DtoAllocaDump(DValue *val, const char *name) {
return DtoAllocaDump(val, val->type, name);
}
LLValue *DtoAllocaDump(DValue *val, int alignment, const char *name) {
return DtoAllocaDump(val, DtoType(val->type), alignment, name);
}
LLValue *DtoAllocaDump(DValue *val, Type *asType, const char *name) {
return DtoAllocaDump(val, DtoType(asType), DtoAlignment(asType), name);
}
LLValue *DtoAllocaDump(DValue *val, LLType *asType, int alignment,
const char *name) {
if (val->isLVal()) {
LLValue *lval = DtoLVal(val);
LLType *asMemType = i1ToI8(voidToI8(asType));
LLValue *copy = DtoRawAlloca(asMemType, alignment, name);
const auto minSize =
std::min(getTypeAllocSize(lval->getType()->getPointerElementType()),
getTypeAllocSize(asMemType));
const auto minAlignment =
std::min(DtoAlignment(val->type), static_cast<unsigned>(alignment));
DtoMemCpy(copy, lval, DtoConstSize_t(minSize), minAlignment);
// TODO: zero-out any remaining bytes?
return copy;
}
return DtoAllocaDump(DtoRVal(val), asType, alignment, name);
}

View file

@ -51,6 +51,7 @@ llvm::AllocaInst *DtoRawAlloca(LLType *lltype, size_t alignment,
LLValue *DtoGcMalloc(Loc &loc, LLType *lltype, const char *name = "");
LLValue *DtoAllocaDump(DValue *val, const char *name = "");
LLValue *DtoAllocaDump(DValue *val, int alignment, const char *name = "");
LLValue *DtoAllocaDump(DValue *val, Type *asType, const char *name = "");
LLValue *DtoAllocaDump(DValue *val, LLType *asType, int alignment = 0,
const char *name = "");

View file

@ -109,8 +109,8 @@ LLFunctionType *DtoExtractFunctionType(LLType *type) {
static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
IrFuncTy &irFty, LLFunctionType *calleeType,
const std::vector<DValue *> &argvals,
int numFormalParams) {
Expressions &argexps,
Parameters *formalParams) {
// Number of arguments added to the LLVM type that are implicit on the
// frontend side of things (this, context pointers, etc.)
const size_t implicitLLArgCount = args.size();
@ -118,14 +118,17 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
// Number of formal arguments in the LLVM type (i.e. excluding varargs).
const size_t formalLLArgCount = irFty.args.size();
// Number of formal arguments in the D call expression (excluding varargs).
const int formalDArgCount = Parameter::dim(formalParams);
// The number of explicit arguments in the D call expression (including
// varargs), not all of which necessarily generate a LLVM argument.
const size_t explicitDArgCount = argvals.size();
const size_t explicitDArgCount = argexps.size();
// construct and initialize an IrFuncTyArg object for each vararg
std::vector<IrFuncTyArg *> optionalIrArgs;
for (size_t i = numFormalParams; i < explicitDArgCount; i++) {
Type *argType = argvals[i]->type;
for (size_t i = formalDArgCount; i < explicitDArgCount; i++) {
Type *argType = argexps[i]->type;
bool passByVal = gABI->passByVal(argType);
AttrBuilder initialAttrs;
@ -148,25 +151,37 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
// Iterate the explicit arguments from left to right in the D source,
// which is the reverse of the LLVM order if irFty.reverseParams is true.
for (size_t i = 0; i < explicitLLArgCount; ++i) {
const bool isVararg = (i >= irFty.args.size());
size_t dArgIndex = 0;
for (size_t i = 0; i < explicitLLArgCount; ++i, ++dArgIndex) {
const bool isVararg = (i >= formalLLArgCount);
IrFuncTyArg *irArg = nullptr;
if (isVararg) {
irArg = optionalIrArgs[i - numFormalParams];
irArg = optionalIrArgs[i - formalLLArgCount];
} else {
irArg = irFty.args[i];
}
DValue *const argval = argvals[irArg->parametersIdx];
Type *const argType = argval->type;
llvm::Value *llVal = nullptr;
if (isVararg) {
llVal = irFty.putParam(*irArg, argval);
} else {
llVal = irFty.putParam(i, argval);
// Make sure to evaluate argument expressions for which there's no LL
// parameter (e.g., empty structs for some ABIs).
for (; dArgIndex < irArg->parametersIdx; ++dArgIndex) {
toElem(argexps[dArgIndex]);
}
Expression *const argexp = argexps[dArgIndex];
Parameter *const formalParam =
isVararg ? nullptr : Parameter::getNth(formalParams, dArgIndex);
// evaluate argument expression
DValue *const dval = DtoArgument(formalParam, argexp);
// check whether it is an lvalue which might be modified by later argument
// expressions
const bool isModifiableLvalue =
argexp->isLvalue() && dArgIndex != explicitDArgCount - 1;
// load from lvalue/let TargetABI rewrite it/...
llvm::Value *llVal = irFty.putParam(*irArg, dval, isModifiableLvalue);
const size_t llArgIdx =
implicitLLArgCount +
(irFty.reverseParams ? explicitLLArgCount - i - 1 : i);
@ -176,7 +191,7 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
// Hack around LDC assuming structs and static arrays are in memory:
// If the function wants a struct, and the argument value is a
// pointer to a struct, load from it before passing it in.
if (isaPointer(llVal) && DtoIsInMemoryOnly(argType) &&
if (isaPointer(llVal) && DtoIsInMemoryOnly(argexp->type) &&
((!isVararg && !isaPointer(paramType)) ||
(isVararg && !irArg->byref && !irArg->isByVal()))) {
Logger::println("Loading struct type for function argument");
@ -203,12 +218,15 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
delete irArg;
}
}
for (; dArgIndex < explicitDArgCount; ++dArgIndex) {
toElem(argexps[dArgIndex]);
}
}
////////////////////////////////////////////////////////////////////////////////
static LLValue *
getTypeinfoArrayArgumentForDVarArg(const std::vector<DValue *> &argvals,
static LLValue *getTypeinfoArrayArgumentForDVarArg(Expressions *argexps,
int begin) {
IF_LOG Logger::println("doing d-style variadic arguments");
LOG_SCOPE
@ -216,7 +234,8 @@ getTypeinfoArrayArgumentForDVarArg(const std::vector<DValue *> &argvals,
// number of non variadic args
IF_LOG Logger::println("num non vararg params = %d", begin);
const size_t numVariadicArgs = argvals.size() - begin;
const size_t numArgExps = argexps ? argexps->size() : 0;
const size_t numVariadicArgs = numArgExps - begin;
// build type info array
LLType *typeinfotype = DtoType(Type::dtypeinfo->type);
@ -229,9 +248,9 @@ getTypeinfoArrayArgumentForDVarArg(const std::vector<DValue *> &argvals,
IF_LOG Logger::cout() << "_arguments storage: " << *typeinfomem << '\n';
std::vector<LLConstant *> vtypeinfos;
vtypeinfos.reserve(argvals.size());
for (size_t i = begin; i < argvals.size(); i++) {
vtypeinfos.push_back(DtoTypeInfoOf(argvals[i]->type));
vtypeinfos.reserve(numVariadicArgs);
for (size_t i = begin; i < numArgExps; i++) {
vtypeinfos.push_back(DtoTypeInfoOf((*argexps)[i]->type));
}
// apply initializer
@ -636,10 +655,9 @@ class ImplicitArgumentsBuilder {
public:
ImplicitArgumentsBuilder(std::vector<LLValue *> &args, AttrSet &attrs,
Loc &loc, DValue *fnval,
LLFunctionType *llCalleeType,
const std::vector<DValue *> &argvals,
LLFunctionType *llCalleeType, Expressions *argexps,
Type *resulttype, LLValue *sretPointer)
: args(args), attrs(attrs), loc(loc), fnval(fnval), argvals(argvals),
: args(args), attrs(attrs), loc(loc), fnval(fnval), argexps(argexps),
resulttype(resulttype), sretPointer(sretPointer),
// computed:
isDelegateCall(fnval->type->toBasetype()->ty == Tdelegate),
@ -665,7 +683,7 @@ private:
AttrSet &attrs;
Loc &loc;
DValue *const fnval;
const std::vector<DValue *> &argvals;
Expressions *const argexps;
Type *const resulttype;
LLValue *const sretPointer;
@ -786,7 +804,7 @@ private:
int numFormalParams = Parameter::dim(tf->parameters);
LLValue *argumentsArg =
getTypeinfoArrayArgumentForDVarArg(argvals, numFormalParams);
getTypeinfoArrayArgumentForDVarArg(argexps, numFormalParams);
args.push_back(argumentsArg);
attrs.addToParam(args.size() - 1, irFty.arg_arguments->attrs);
@ -795,45 +813,12 @@ private:
////////////////////////////////////////////////////////////////////////////////
namespace {
std::vector<DValue *> evaluateArgExpressions(DValue *fnval,
Expressions *arguments) {
IF_LOG Logger::println("Evaluating argument expressions");
LOG_SCOPE
const auto tf = DtoTypeFunction(fnval);
const size_t numArguments = arguments ? arguments->dim : 0;
std::vector<DValue *> argvals(numArguments);
// formal params (excl. variadics)
size_t i = 0;
const size_t numFormalParams = Parameter::dim(tf->parameters);
for (; i < numFormalParams; ++i) {
Parameter *fnarg = Parameter::getNth(tf->parameters, i);
assert(fnarg);
argvals[i] = DtoArgument(fnarg, (*arguments)[i]);
}
// append variadics
for (; i < numArguments; ++i) {
argvals[i] = DtoArgument(nullptr, (*arguments)[i]);
}
return argvals;
}
}
////////////////////////////////////////////////////////////////////////////////
// FIXME: this function is a mess !
DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
Expressions *arguments, LLValue *sretPointer) {
IF_LOG Logger::println("DtoCallFunction()");
LOG_SCOPE
const auto argvals = evaluateArgExpressions(fnval, arguments);
// make sure the D callee type has been processed
DtoType(fnval->type);
@ -871,7 +856,7 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
args.reserve(irFty.args.size());
// handle implicit arguments (sret, context/this, _arguments)
ImplicitArgumentsBuilder iab(args, attrs, loc, fnval, callableTy, argvals,
ImplicitArgumentsBuilder iab(args, attrs, loc, fnval, callableTy, arguments,
resulttype, sretPointer);
iab.addImplicitArgs();
@ -889,9 +874,10 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
// Logger::cout() << "LLVM functype: " << *callable->getType() << '\n';
}
const int numFormalParams = Parameter::dim(tf->parameters); // excl. variadics
addExplicitArguments(args, attrs, irFty, callableTy, argvals,
numFormalParams);
if (arguments) {
addExplicitArguments(args, attrs, irFty, callableTy, *arguments,
tf->parameters);
}
if (irFty.arg_objcSelector) {
// Use runtime msgSend function bitcasted as original call

View file

@ -239,15 +239,9 @@ public:
// adding more control flow.
if (result && result->type->ty != Tvoid &&
!result->definedInFuncEntryBB()) {
if (result->isLVal()) {
LLValue *copy = DtoAlloca(result->type);
DtoMemCpy(copy, DtoLVal(result));
result = new DLValue(result->type, copy);
} else {
LLValue *copy = DtoAllocaDump(result);
result = new DLValue(result->type, copy);
}
}
llvm::BasicBlock *endbb = p->insertBB("toElem.success");
p->funcGen().scopes.runCleanups(initialCleanupScope, endbb);
@ -1616,7 +1610,9 @@ public:
} else if (e->e1->op == TOKvar) {
if (auto vd = static_cast<VarExp *>(e->e1)->var->isVarDeclaration()) {
if (vd->onstack) {
DtoFinalizeClass(e->loc, DtoRVal(dval));
assert(vd->scopeClassType);
const auto cd = vd->scopeClassType->sym->isClassDeclaration();
DtoFinalizeScopeClass(e->loc, DtoRVal(dval), cd);
onstack = true;
}
}

View file

@ -275,7 +275,6 @@ llvm::GetElementPtrInst *DtoGEP(LLValue *ptr, llvm::ArrayRef<LLValue *> indices,
bool inBounds, const char *name,
llvm::BasicBlock *bb) {
LLPointerType *p = isaPointer(ptr);
(void)p;
assert(p && "GEP expects a pointer type");
auto gep = llvm::GetElementPtrInst::Create(
p->getElementType(), ptr, indices, name, bb ? bb : gIR->scopebb());

View file

@ -33,7 +33,7 @@ llvm::Value *IrFuncTy::putRet(DValue *dval) {
if (ret->rewrite) {
Logger::println("Rewrite: putRet");
LOG_SCOPE
return ret->rewrite->put(dval);
return ret->rewrite->put(dval, /*isModifiableLvalue=*/false);
}
if (ret->byref || DtoIsInMemoryOnly(dval->type))
@ -66,20 +66,20 @@ llvm::Value *IrFuncTy::getRetLVal(Type *dty, LLValue *val) {
return DtoAllocaDump(val, dty);
}
llvm::Value *IrFuncTy::putParam(size_t idx, DValue *dval) {
assert(idx < args.size() && "invalid putParam");
return putParam(*args[idx], dval);
}
llvm::Value *IrFuncTy::putParam(const IrFuncTyArg &arg, DValue *dval) {
llvm::Value *IrFuncTy::putParam(const IrFuncTyArg &arg, DValue *dval,
bool isModifiableLvalue) {
if (arg.rewrite) {
Logger::println("Rewrite: putParam");
LOG_SCOPE
return arg.rewrite->put(dval);
return arg.rewrite->put(dval, isModifiableLvalue);
}
if (arg.byref || DtoIsInMemoryOnly(dval->type))
if (arg.byref || DtoIsInMemoryOnly(dval->type)) {
if (isModifiableLvalue && arg.isByVal()) {
return DtoAllocaDump(dval, ".lval_copy_for_byval");
}
return DtoLVal(dval);
}
return DtoRVal(dval);
}

View file

@ -111,8 +111,8 @@ struct IrFuncTy {
llvm::Value *getRetRVal(Type *dty, llvm::Value *val);
llvm::Value *getRetLVal(Type *dty, llvm::Value *val);
llvm::Value *putParam(size_t idx, DValue *dval);
llvm::Value *putParam(const IrFuncTyArg &arg, DValue *dval);
llvm::Value *putParam(const IrFuncTyArg &arg, DValue *dval,
bool isModifiableLvalue);
llvm::Value *getParamLVal(Type *dty, size_t idx, llvm::Value *val);
AttrSet getParamAttrs(bool passThisBeforeSret);

View file

@ -630,9 +630,8 @@ macro(build_all_runtime_variants d_flags c_flags ld_flags path_suffix outlist_ta
build_runtime_variants("${d_flags}" "${c_flags}" "${ld_flags}" "${path_suffix}" ${outlist_targets})
# static profile-rt
build_profile_runtime("${d_flags};${D_FLAGS};${D_FLAGS_RELEASE}" "${c_flags}" "${ld_flags}" "" "${path_suffix}" ${outlist_targets})
build_profile_runtime("${c_flags}" "${ld_flags}" "" "${path_suffix}" ${outlist_targets})
get_target_suffix("" "${path_suffix}" target_suffix)
set_common_library_properties(ldc-profile-rt${target_suffix} OFF)
endmacro()

View file

@ -70,15 +70,16 @@ struct RtCompileVarList {
};
struct RtCompileModuleList {
int32_t version;
RtCompileModuleList *next;
const char *irData;
int irDataSize;
int32_t irDataSize;
const RtCompileFuncList *funcList;
int funcListSize;
int32_t funcListSize;
const RtCompileSymList *symList;
int symListSize;
int32_t symListSize;
const RtCompileVarList *varList;
int varListSize;
int32_t varListSize;
};
#pragma pack(pop)
@ -347,9 +348,15 @@ struct JitFinaliser final {
};
template <typename F>
void enumModules(const RtCompileModuleList *modlist_head, F &&fun) {
void enumModules(const RtCompileModuleList *modlist_head,
const Context& context,
F &&fun) {
auto current = modlist_head;
while (current != nullptr) {
interruptPoint(context, "check version");
if (current->version != ApiVersion) {
fatal(context, "Module was built with different jit api version");
}
fun(*current);
current = current->next;
}
@ -370,7 +377,7 @@ void rtCompileProcessImplSoInternal(const RtCompileModuleList *modlist_head,
OptimizerSettings settings;
settings.optLevel = context.optLevel;
settings.sizeLevel = context.sizeLevel;
enumModules(modlist_head, [&](const RtCompileModuleList &current) {
enumModules(modlist_head, context, [&](const RtCompileModuleList &current) {
interruptPoint(context, "load IR");
auto buff = llvm::MemoryBuffer::getMemBuffer(
llvm::StringRef(current.irData,
@ -476,7 +483,7 @@ __declspec(dllexport)
#else
__attribute__ ((visibility ("default")))
#endif
void rtCompileProcessImplSo(const void *modlist_head,
void JIT_API_ENTRYPOINT(const void *modlist_head,
const Context *context, size_t contextSize) {
assert(nullptr != context);
assert(sizeof(*context) == contextSize);

View file

@ -23,6 +23,16 @@ enum class DumpStage : int {
FinalAsm = 3
};
enum {
ApiVersion = LDC_DYNAMIC_COMPILE_API_VERSION
};
#define MAKE_JIT_API_CALL_IMPL(prefix, version) prefix##version
#define MAKE_JIT_API_CALL(prefix, version) \
MAKE_JIT_API_CALL_IMPL(prefix, version)
#define JIT_API_ENTRYPOINT MAKE_JIT_API_CALL(rtCompileProcessImplSo, \
LDC_DYNAMIC_COMPILE_API_VERSION)
typedef void (*InterruptPointHandlerT)(void *, const char *action,
const char *object);
typedef void (*FatalHandlerT)(void *, const char *reason);

View file

@ -266,7 +266,7 @@ void disassemble(const llvm::TargetMachine &tm,
llvm::MCTargetOptions opts;
auto mab = unique(target.createMCAsmBackend(
#if LDC_LLVM_VER >= 700
#if LDC_LLVM_VER >= 600
*sti, *mri, opts)
#else
*mri, tm.getTargetTriple().getTriple(), tm.getTargetCPU(), opts)

View file

@ -16,6 +16,12 @@
struct Context;
#define MAKE_JIT_API_CALL_IMPL(prefix, version) prefix##version
#define MAKE_JIT_API_CALL(prefix, version) \
MAKE_JIT_API_CALL_IMPL(prefix, version)
#define JIT_API_ENTRYPOINT MAKE_JIT_API_CALL(rtCompileProcessImplSo, \
LDC_DYNAMIC_COMPILE_API_VERSION)
extern "C" {
// Silence missing-variable-declaration clang warning
@ -25,11 +31,11 @@ const void *dynamiccompile_modules_head = nullptr;
#ifdef _WIN32
__declspec(dllimport)
#endif
extern void rtCompileProcessImplSo(const void *modlist_head,
extern void JIT_API_ENTRYPOINT(const void *modlist_head,
const Context *context,
std::size_t contextSize);
void rtCompileProcessImpl(const Context *context, std::size_t contextSize) {
rtCompileProcessImplSo(dynamiccompile_modules_head, context, contextSize);
JIT_API_ENTRYPOINT(dynamiccompile_modules_head, context, contextSize);
}
}

View file

@ -1,7 +1,5 @@
# Add LLVM Profile runtime for PGO
file(GLOB LDC_PROFRT_D ${PROFILERT_DIR}/d/ldc/*.d)
# Choose the correct subfolder depending on the LLVM version
set(PROFILERT_LIBSRC_DIR "${PROFILERT_DIR}/profile-rt-${LLVM_VERSION_MAJOR}${LLVM_VERSION_MINOR}")
file(GLOB LDC_PROFRT_C ${PROFILERT_LIBSRC_DIR}/*.c)
@ -72,29 +70,12 @@ if(COMPILER_RT_TARGET_HAS_UNAME)
set(PROFRT_EXTRA_FLAGS "${PROFRT_EXTRA_FLAGS} -DCOMPILER_RT_HAS_UNAME=1")
endif()
# Sets up the targets for building the D-source profile-rt object files,
# appending the names of the (bitcode) files to link into the library to
# outlist_o (outlist_bc).
macro(compile_profilert_D d_flags lib_suffix path_suffix all_at_once outlist_o outlist_bc)
get_target_suffix("${lib_suffix}" "${path_suffix}" target_suffix)
dc("${LDC_PROFRT_D}"
"${PROFILERT_DIR}/d"
"${d_flags}"
"${PROJECT_BINARY_DIR}/objects${target_suffix}"
"${all_at_once}"
${outlist_o}
${outlist_bc}
)
endmacro()
macro(build_profile_runtime d_flags c_flags ld_flags lib_suffix path_suffix outlist_targets)
macro(build_profile_runtime c_flags ld_flags lib_suffix path_suffix outlist_targets)
set(output_path ${CMAKE_BINARY_DIR}/lib${path_suffix})
set(profilert_d_o "")
set(profilert_d_bc "")
compile_profilert_D("${d_flags};-relocation-model=pic" "${lib_suffix}" "${path_suffix}" "${COMPILE_ALL_D_FILES_AT_ONCE}" profilert_d_o profilert_d_bc)
get_target_suffix("${lib_suffix}" "${path_suffix}" target_suffix)
add_library(ldc-profile-rt${target_suffix} STATIC ${profilert_d_o} ${LDC_PROFRT_C} ${LDC_PROFRT_CXX})
add_library(ldc-profile-rt${target_suffix} STATIC ${LDC_PROFRT_C} ${LDC_PROFRT_CXX})
set_target_properties(
ldc-profile-rt${target_suffix} PROPERTIES
OUTPUT_NAME ldc-profile-rt${lib_suffix}
@ -111,4 +92,4 @@ macro(build_profile_runtime d_flags c_flags ld_flags lib_suffix path_suffix outl
endmacro()
# Install D interface files to profile-rt.
install(DIRECTORY ${PROFILERT_DIR}/d/ldc DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.d")
install(DIRECTORY ${PROFILERT_DIR}/d/ldc DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.di")

View file

@ -3,11 +3,16 @@
* instrumented programs (compiled with -fprofile-instr-generate).
* It provides an interface to the profile-rt runtime library.
*
* Note that this only works for instrumented binaries.
* The functions in this module only work for PGO-instrumented binaries.
*
* Copyright: Authors 2016-2016
* License: University of Illinois Open Source License and MIT License. See LDC's LICENSE for details.
* Authors: Johan B C Engelen
* This module is template-only, and is not compiled nor linked into druntime.
* This way, LDC does not need its own profile-rt library and LDC can directly
* use compiler-rt's profile runtime library.
*
* Copyright: Authors 2016-2018
* License: University of Illinois Open Source License and MIT License.
* See LDC's LICENSE for details.
* Authors: LDC Team
*/
module ldc.profile;
@ -101,7 +106,6 @@ extern(C++) struct ProfileData {
}
// Symbols provided by profile-rt lib
private {
extern(C) {
alias uint64_t = ulong;
alias __llvm_profile_data = ProfileData;
@ -115,16 +119,14 @@ extern(C) {
void __llvm_profile_reset_counters();
uint64_t __llvm_profile_get_magic();
uint64_t __llvm_profile_get_version();
}}
}
/**
* Reset all profiling information of the whole program.
* This can be used for example to remove transient start-up behavior from the
* profile.
*/
void resetAll() {
__llvm_profile_reset_counters();
}
alias resetAll = __llvm_profile_reset_counters;
/**
* Reset profile counter values for a function.

View file

@ -0,0 +1,47 @@
// RUN: %ldc -run %s
void checkInt(int a, int b, int c)
{
assert(a == 1);
assert(b == 2);
assert(c == 3);
}
int incrementBy2AndReturn2(ref int a)
{
a += 2;
return 2;
}
// ---
struct BigStruct
{
long[33] blub;
int v;
this(int v) { this.v = v; }
}
void checkBigStruct(BigStruct a, BigStruct b, BigStruct c)
{
assert(a.v == 1);
assert(b.v == 2);
assert(c.v == 3);
}
BigStruct incrementBy2AndReturn2(ref BigStruct a)
{
a.v += 2;
return BigStruct(2);
}
// ---
void main()
{
int a = 1;
checkInt(a, incrementBy2AndReturn2(a), a);
auto s = BigStruct(1);
checkBigStruct(s, incrementBy2AndReturn2(s), s);
}

81
tests/codegen/gh2515.d Normal file
View file

@ -0,0 +1,81 @@
// For scope-allocated class objects, make sure the _d_callfinalizer()
// druntime call is elided if the object has no dtors and no monitor.
// RUN: %ldc -O3 -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
import core.stdc.stdio : printf;
class Base
{
int val = 123;
void foo() { val *= 3; }
void bar() { synchronized(this) val *= 2; }
}
class WithDtor : Base
{
~this() {}
}
class WithImplicitDtor : Base
{
static struct S { int val; ~this() {} }
S s;
}
// CHECK: define{{.*}} void @{{.*}}_D6gh251516noDtor_noMonitorFZv
void noDtor_noMonitor()
{
scope b = new Base();
b.foo();
printf("%d\n", b.val);
// CHECK-NOT: _d_callfinalizer
// CHECK: ret void
}
// CHECK: define{{.*}} void @{{.*}}_D6gh251518noDtor_withMonitorFZv
void noDtor_withMonitor()
{
scope b = new Base();
b.bar();
printf("%d\n", b.val);
// CHECK: _d_callfinalizer
// CHECK: ret void
}
// CHECK: define{{.*}} void @{{.*}}_D6gh25158withDtorFZv
void withDtor()
{
scope Base b = new WithDtor();
b.foo();
printf("%d\n", b.val);
// CHECK: _d_callfinalizer
// CHECK: ret void
}
// CHECK: define{{.*}} void @{{.*}}_D6gh251516withImplicitDtorFZv
void withImplicitDtor()
{
scope Base b = new WithImplicitDtor();
b.foo();
printf("%d\n", b.val);
// CHECK: _d_callfinalizer
// CHECK: ret void
}
/* Test a C++ class as well, which as of 2.077 isn't implicitly delete()d. */
extern(C++) class CppClass
{
int val = 666;
}
// CHECK: define{{.*}} void @{{.*}}_D6gh25158cppClassFZv
void cppClass()
{
scope c = new CppClass();
printf("%d\n", c.val);
// CHECK-NOT: _d_callfinalizer
// CHECK: ret void
}

View file

@ -0,0 +1,10 @@
import os
import platform
import re
# Add "XRay_RT" feature if the runtime library is available
for file in os.listdir(config.ldc2_lib_dir):
m = re.match('.*xray.*', file)
if m is not None:
config.available_features.add('XRay')
continue

View file

@ -0,0 +1,11 @@
// Check that the LLVM pipeline is set up correctly to generate XRay sleds.
// If we have the XRay runtime lib for this platform, then we can also do machinecodegen:
// REQUIRES: XRay_RT
// RUN: %ldc -c -output-s -betterC -fxray-instrument -fxray-instruction-threshold=1 -of=%t.s %s && FileCheck %s < %t.s
// CHECK: xray_sled
void instrument()
{
}

View file

@ -0,0 +1,21 @@
// REQUIRES: atleast_llvm500
// RUN: %ldc -c -output-ll -fxray-instrument -of=%t.ll %s && FileCheck %s < %t.ll
import ldc.attributes;
// CHECK-LABEL: define{{.*}} @{{.*}}10instrument
// CHECK-SAME: #[[INSTR:[0-9]+]]
void instrument()
{
}
// CHECK-LABEL: define{{.*}} @{{.*}}15dont_instrument
// CHECK-SAME: #[[DONT_INSTR:[0-9]+]]
void dont_instrument()
{
pragma(LDC_profile_instr, false);
}
// CHECK-DAG: attributes #[[INSTR]] ={{.*}} "xray-instruction-threshold"=
// CHECK-DAG: attributes #[[DONT_INSTR]] ={{.*}} "function-instrument"="xray-never"

View file

@ -0,0 +1,11 @@
// REQUIRES: atleast_llvm500
// RUN: %ldc -c -output-ll -fxray-instrument -fxray-instruction-threshold=543 -of=%t.ll %s && FileCheck %s < %t.ll
// CHECK-LABEL: define{{.*}} @{{.*}}10instrument
// CHECK-SAME: #[[INSTR:[0-9]+]]
void instrument()
{
}
// CHECK-DAG: attributes #[[INSTR]] ={{.*}} "xray-instruction-threshold"="543"

View file

@ -0,0 +1,15 @@
// REQUIRES: XRay_RT
// RUN: %ldc -fxray-instrument -fxray-instruction-threshold=1 -of=%t%exe %s -vv | FileCheck %s
void foo()
{
}
void main()
{
foo();
}
// CHECK: Linking with:
// CHECK-NEXT: rt.xray