mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-06 02:45:25 +03:00
Merge branch 'master' into merge-2.078
This commit is contained in:
commit
1b860e70d7
45 changed files with 579 additions and 200 deletions
|
@ -388,6 +388,7 @@ if(LDC_DYNAMIC_COMPILE STREQUAL "AUTO")
|
||||||
set(LDC_DYNAMIC_COMPILE True)
|
set(LDC_DYNAMIC_COMPILE True)
|
||||||
message(STATUS "Building LDC with dynamic compilation support")
|
message(STATUS "Building LDC with dynamic compilation support")
|
||||||
add_definitions(-DLDC_DYNAMIC_COMPILE)
|
add_definitions(-DLDC_DYNAMIC_COMPILE)
|
||||||
|
add_definitions(-DLDC_DYNAMIC_COMPILE_API_VERSION=1)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -745,9 +746,7 @@ else()
|
||||||
endif()
|
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.")
|
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)
|
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
|
set(llvm_lib_path ${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_BASE_STRING}/lib/${llvm_lib_name})
|
||||||
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})
|
|
||||||
if(EXISTS ${llvm_lib_path})
|
if(EXISTS ${llvm_lib_path})
|
||||||
message(STATUS "Copying runtime library: ${llvm_lib_path} --> ${ldc_lib_name}")
|
message(STATUS "Copying runtime library: ${llvm_lib_path} --> ${ldc_lib_name}")
|
||||||
set(ldc_lib_path ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/${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)
|
copy_compilerrt_lib("darwin/libclang_rt.asan_osx_dynamic.dylib" "libldc_rt.asan_osx_dynamic.dylib" TRUE)
|
||||||
if(NOT (LDC_LLVM_VER LESS 600))
|
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.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()
|
endif()
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
copy_compilerrt_lib("linux/libclang_rt.asan-x86_64.a" "libldc_rt.asan-x86_64.a" FALSE)
|
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))
|
if(NOT (LDC_LLVM_VER LESS 600))
|
||||||
copy_compilerrt_lib("linux/libclang_rt.fuzzer-x86_64.a" "libldc_rt.fuzzer-x86_64.a" FALSE)
|
copy_compilerrt_lib("linux/libclang_rt.fuzzer-x86_64.a" "libldc_rt.fuzzer-x86_64.a" FALSE)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
# llvm-config is searched for in ${LLVM_ROOT_DIR}/bin.
|
# llvm-config is searched for in ${LLVM_ROOT_DIR}/bin.
|
||||||
# LLVM_VERSION_MAJOR - Major version of LLVM.
|
# LLVM_VERSION_MAJOR - Major version of LLVM.
|
||||||
# LLVM_VERSION_MINOR - Minor 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
|
# Note: The variable names were chosen in conformance with the offical CMake
|
||||||
# guidelines, see ${CMAKE_ROOT}/Modules/readme.txt.
|
# guidelines, see ${CMAKE_ROOT}/Modules/readme.txt.
|
||||||
|
@ -105,6 +106,9 @@ else()
|
||||||
llvm_set(ROOT_DIR prefix true)
|
llvm_set(ROOT_DIR prefix true)
|
||||||
llvm_set(ENABLE_ASSERTIONS assertion-mode)
|
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]*")
|
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-8][\\.0-9A-Za-z]*")
|
||||||
# Versions below 3.9 do not support components debuginfocodeview, globalisel
|
# Versions below 3.9 do not support components debuginfocodeview, globalisel
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfocodeview" index)
|
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfocodeview" index)
|
||||||
|
|
|
@ -1012,6 +1012,11 @@ extern (C++) class VarDeclaration : Declaration
|
||||||
Expression edtor; // if !=null, does the destruction of the variable
|
Expression edtor; // if !=null, does the destruction of the variable
|
||||||
IntRange* range; // if !=null, the variable is known to be within the range
|
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)
|
final extern (D) this(Loc loc, Type type, Identifier id, Initializer _init, StorageClass storage_class = STCundefined)
|
||||||
{
|
{
|
||||||
super(id);
|
super(id);
|
||||||
|
|
|
@ -267,6 +267,10 @@ public:
|
||||||
Expression *edtor; // if !=NULL, does the destruction of the variable
|
Expression *edtor; // if !=NULL, does the destruction of the variable
|
||||||
IntRange *range; // if !NULL, the variable is known to be within the range
|
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 *);
|
Dsymbol *syntaxCopy(Dsymbol *);
|
||||||
void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
|
void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
|
||||||
const char *kind() const;
|
const char *kind() const;
|
||||||
|
|
|
@ -2585,6 +2585,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||||
{
|
{
|
||||||
ne.onstack = 1;
|
ne.onstack = 1;
|
||||||
dsym.onstack = true;
|
dsym.onstack = true;
|
||||||
|
version (IN_LLVM)
|
||||||
|
{
|
||||||
|
dsym.scopeClassType = cast(TypeClass) ne.newtype;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
#include "gen/to_string.h"
|
||||||
|
#include "llvm/ADT/Triple.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
namespace cl = llvm::cl;
|
namespace cl = llvm::cl;
|
||||||
|
@ -51,6 +53,15 @@ cl::opt<std::string> ASTPGOInstrUseFile(
|
||||||
cl::desc("Use instrumentation data for profile-guided optimization"),
|
cl::desc("Use instrumentation data for profile-guided optimization"),
|
||||||
cl::ValueRequired);
|
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
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace opts {
|
namespace opts {
|
||||||
|
@ -67,7 +78,21 @@ static cl::opt<bool> dmdFunctionTrace(
|
||||||
"fdmd-trace-functions", cl::ZeroOrMore,
|
"fdmd-trace-functions", cl::ZeroOrMore,
|
||||||
cl::desc("DMD-style runtime performance profiling of generated code"));
|
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) {
|
if (ASTPGOInstrGenFile.getNumOccurrences() > 0) {
|
||||||
pgoMode = PGO_ASTBasedInstr;
|
pgoMode = PGO_ASTBasedInstr;
|
||||||
if (ASTPGOInstrGenFile.empty()) {
|
if (ASTPGOInstrGenFile.empty()) {
|
||||||
|
@ -101,9 +126,7 @@ void initializeInstrumentationOptionsFromCmdline() {
|
||||||
// There is a bug in (our use of?) LLVM where codegen errors with
|
// 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
|
// PGO_IRBasedInstr for Windows targets. So disable IRBased PGO on Windows for
|
||||||
// now.
|
// now.
|
||||||
assert(global.params.targetTriple);
|
if ((pgoMode == PGO_IRBasedInstr) && triple.isOSWindows()) {
|
||||||
if ((pgoMode == PGO_IRBasedInstr) &&
|
|
||||||
global.params.targetTriple->isOSWindows()) {
|
|
||||||
error(Loc(),
|
error(Loc(),
|
||||||
"'-fprofile-generate' is not yet supported for Windows targets.");
|
"'-fprofile-generate' is not yet supported for Windows targets.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,15 +18,26 @@
|
||||||
|
|
||||||
#include "gen/cl_helpers.h"
|
#include "gen/cl_helpers.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
class Triple;
|
||||||
|
}
|
||||||
|
|
||||||
namespace opts {
|
namespace opts {
|
||||||
namespace cl = llvm::cl;
|
namespace cl = llvm::cl;
|
||||||
|
|
||||||
extern cl::opt<bool> instrumentFunctions;
|
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
|
/// This initializes the instrumentation options, and checks the validity of the
|
||||||
/// commandline flags. targetTriple should be initialized before calling this.
|
/// commandline flags. targetTriple should be initialized before calling this.
|
||||||
/// It should be called only once.
|
/// It should be called only once.
|
||||||
void initializeInstrumentationOptionsFromCmdline();
|
void initializeInstrumentationOptionsFromCmdline(const llvm::Triple &triple);
|
||||||
|
|
||||||
enum PGOKind {
|
enum PGOKind {
|
||||||
PGO_None,
|
PGO_None,
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace ldc {
|
||||||
const char * const ldc_version = "@LDC_VERSION@";
|
const char * const ldc_version = "@LDC_VERSION@";
|
||||||
const char * const dmd_version = "v@DMD_VERSION@";
|
const char * const dmd_version = "v@DMD_VERSION@";
|
||||||
const char * const llvm_version = "@LLVM_VERSION_STRING@";
|
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@";
|
const char * const built_with_Dcompiler_version = "@D_COMPILER_VERSION_STRING@";
|
||||||
|
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@ namespace ldc {
|
||||||
extern const char *const ldc_version;
|
extern const char *const ldc_version;
|
||||||
extern const char *const dmd_version;
|
extern const char *const dmd_version;
|
||||||
extern const char *const llvm_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;
|
extern const char *const built_with_Dcompiler_version;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "driver/cl_options_instrumentation.h"
|
#include "driver/cl_options_instrumentation.h"
|
||||||
#include "driver/cl_options_sanitizers.h"
|
#include "driver/cl_options_sanitizers.h"
|
||||||
#include "driver/exe_path.h"
|
#include "driver/exe_path.h"
|
||||||
|
#include "driver/ldc-version.h"
|
||||||
#include "driver/tool.h"
|
#include "driver/tool.h"
|
||||||
#include "gen/irstate.h"
|
#include "gen/irstate.h"
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
|
@ -52,6 +53,7 @@ private:
|
||||||
virtual void addASanLinkFlags(const llvm::Triple &triple);
|
virtual void addASanLinkFlags(const llvm::Triple &triple);
|
||||||
virtual void addFuzzLinkFlags(const llvm::Triple &triple);
|
virtual void addFuzzLinkFlags(const llvm::Triple &triple);
|
||||||
virtual void addCppStdlibLinkFlags(const llvm::Triple &triple);
|
virtual void addCppStdlibLinkFlags(const llvm::Triple &triple);
|
||||||
|
virtual void addXRayLinkFlags(const llvm::Triple &triple);
|
||||||
|
|
||||||
virtual void addLinker();
|
virtual void addLinker();
|
||||||
virtual void addUserSwitches();
|
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) {
|
void ArgsBuilder::addASanLinkFlags(const llvm::Triple &triple) {
|
||||||
// Examples: "libclang_rt.asan-x86_64.a" or "libclang_rt.asan-arm.a" and
|
// Examples: "libclang_rt.asan-x86_64.a" or "libclang_rt.asan-arm.a" and
|
||||||
// "libclang_rt.asan-x86_64.so"
|
// "libclang_rt.asan-x86_64.so"
|
||||||
|
@ -217,12 +249,14 @@ void ArgsBuilder::addASanLinkFlags(const llvm::Triple &triple) {
|
||||||
std::string searchPaths[] = {
|
std::string searchPaths[] = {
|
||||||
getFullCompilerRTLibPath(triple, "libldc_rt.asan", linkSharedASan),
|
getFullCompilerRTLibPath(triple, "libldc_rt.asan", linkSharedASan),
|
||||||
getFullCompilerRTLibPath(triple, "libclang_rt.asan", linkSharedASan),
|
getFullCompilerRTLibPath(triple, "libclang_rt.asan", linkSharedASan),
|
||||||
|
getFullClangCompilerRTLibPath(triple, "libclang_rt.asan", linkSharedASan),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto &filepath : searchPaths) {
|
for (const auto &filepath : searchPaths) {
|
||||||
IF_LOG Logger::println("Searching ASan lib: %s", filepath.c_str());
|
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());
|
IF_LOG Logger::println("Found, linking with %s", filepath.c_str());
|
||||||
args.push_back(filepath);
|
args.push_back(filepath);
|
||||||
|
|
||||||
|
@ -256,6 +290,7 @@ void ArgsBuilder::addFuzzLinkFlags(const llvm::Triple &triple) {
|
||||||
#if LDC_LLVM_VER >= 600
|
#if LDC_LLVM_VER >= 600
|
||||||
getFullCompilerRTLibPath(triple, "libldc_rt.fuzzer"),
|
getFullCompilerRTLibPath(triple, "libldc_rt.fuzzer"),
|
||||||
getFullCompilerRTLibPath(triple, "libclang_rt.fuzzer"),
|
getFullCompilerRTLibPath(triple, "libclang_rt.fuzzer"),
|
||||||
|
getFullClangCompilerRTLibPath(triple, "libclang_rt.fuzzer"),
|
||||||
#else
|
#else
|
||||||
exe_path::prependLibDir("libFuzzer.a"),
|
exe_path::prependLibDir("libFuzzer.a"),
|
||||||
exe_path::prependLibDir("libLLVMFuzzer.a"),
|
exe_path::prependLibDir("libLLVMFuzzer.a"),
|
||||||
|
@ -265,7 +300,8 @@ void ArgsBuilder::addFuzzLinkFlags(const llvm::Triple &triple) {
|
||||||
for (const auto &filepath : searchPaths) {
|
for (const auto &filepath : searchPaths) {
|
||||||
IF_LOG Logger::println("Searching libFuzzer: %s", filepath.c_str());
|
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());
|
IF_LOG Logger::println("Found, linking with %s", filepath.c_str());
|
||||||
args.push_back(filepath);
|
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) {
|
void ArgsBuilder::addCppStdlibLinkFlags(const llvm::Triple &triple) {
|
||||||
if (linkNoCpp)
|
if (linkNoCpp)
|
||||||
return;
|
return;
|
||||||
|
@ -375,6 +437,10 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
|
||||||
|
|
||||||
addSanitizers(*global.params.targetTriple);
|
addSanitizers(*global.params.targetTriple);
|
||||||
|
|
||||||
|
if (opts::fXRayInstrument) {
|
||||||
|
addXRayLinkFlags(*global.params.targetTriple);
|
||||||
|
}
|
||||||
|
|
||||||
#if LDC_LLVM_VER >= 309
|
#if LDC_LLVM_VER >= 309
|
||||||
// Add LTO link flags before adding the user link switches, such that the user
|
// Add LTO link flags before adding the user link switches, such that the user
|
||||||
// can pass additional options to the LTO plugin.
|
// can pass additional options to the LTO plugin.
|
||||||
|
|
|
@ -1064,7 +1064,8 @@ int cppmain(int argc, char **argv) {
|
||||||
global.lib_ext = "a";
|
global.lib_ext = "a";
|
||||||
}
|
}
|
||||||
|
|
||||||
opts::initializeInstrumentationOptionsFromCmdline();
|
opts::initializeInstrumentationOptionsFromCmdline(
|
||||||
|
*global.params.targetTriple);
|
||||||
|
|
||||||
Strings libmodules;
|
Strings libmodules;
|
||||||
return mars_mainBody(files, libmodules);
|
return mars_mainBody(files, libmodules);
|
||||||
|
|
|
@ -146,7 +146,11 @@ class AssemblyAnnotator : public AssemblyAnnotationWriter {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const llvm::DataLayout &DL;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
AssemblyAnnotator(const llvm::DataLayout &dl) : DL{dl} {}
|
||||||
|
|
||||||
void emitFunctionAnnot(const Function *F,
|
void emitFunctionAnnot(const Function *F,
|
||||||
formatted_raw_ostream &os) override {
|
formatted_raw_ostream &os) override {
|
||||||
os << "; [#uses = " << F->getNumUses() << ']';
|
os << "; [#uses = " << F->getNumUses() << ']';
|
||||||
|
@ -172,7 +176,7 @@ public:
|
||||||
os << ", type = " << *val.getType();
|
os << ", type = " << *val.getType();
|
||||||
} else if (isa<AllocaInst>(&val)) {
|
} else if (isa<AllocaInst>(&val)) {
|
||||||
os << ", size/byte = "
|
os << ", size/byte = "
|
||||||
<< gDataLayout->getTypeAllocSize(val.getType()->getContainedType(0));
|
<< DL.getTypeAllocSize(val.getType()->getContainedType(0));
|
||||||
}
|
}
|
||||||
os << ']';
|
os << ']';
|
||||||
}
|
}
|
||||||
|
@ -387,7 +391,7 @@ void writeModule(llvm::Module *m, const char *filename) {
|
||||||
errinfo.message().c_str());
|
errinfo.message().c_str());
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
AssemblyAnnotator annotator;
|
AssemblyAnnotator annotator(m->getDataLayout());
|
||||||
m->print(aos, &annotator);
|
m->print(aos, &annotator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ struct LLTypeMemoryLayout {
|
||||||
|
|
||||||
/// Removes padding fields for (non-union-containing!) structs
|
/// Removes padding fields for (non-union-containing!) structs
|
||||||
struct RemoveStructPadding : ABIRewrite {
|
struct RemoveStructPadding : ABIRewrite {
|
||||||
LLValue *put(DValue *v) override {
|
LLValue *put(DValue *v, bool) override {
|
||||||
return DtoUnpaddedStruct(v->type->toBasetype(), DtoLVal(v));
|
return DtoUnpaddedStruct(v->type->toBasetype(), DtoLVal(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ struct IntegerRewrite : ABIRewrite {
|
||||||
return LLTypeMemoryLayout::typesAreEquivalent(llType, integerType);
|
return LLTypeMemoryLayout::typesAreEquivalent(llType, integerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue *put(DValue *dv) override {
|
LLValue *put(DValue *dv, bool) override {
|
||||||
LLValue *address = getAddressOf(dv);
|
LLValue *address = getAddressOf(dv);
|
||||||
LLType *integerType = getIntegerType(dv->type->size());
|
LLType *integerType = getIntegerType(dv->type->size());
|
||||||
return loadFromMemory(address, integerType);
|
return loadFromMemory(address, integerType);
|
||||||
|
@ -189,20 +189,8 @@ struct ExplicitByvalRewrite : ABIRewrite {
|
||||||
explicit ExplicitByvalRewrite(unsigned minAlignment = 16)
|
explicit ExplicitByvalRewrite(unsigned minAlignment = 16)
|
||||||
: minAlignment(minAlignment) {}
|
: minAlignment(minAlignment) {}
|
||||||
|
|
||||||
LLValue *put(DValue *v) override {
|
LLValue *put(DValue *v, bool) override {
|
||||||
const unsigned align = alignment(v->type);
|
return DtoAllocaDump(v, alignment(v->type), ".ExplicitByvalRewrite_dump");
|
||||||
|
|
||||||
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 *getLVal(Type *dty, LLValue *v) override {
|
LLValue *getLVal(Type *dty, LLValue *v) override {
|
||||||
|
@ -225,7 +213,7 @@ struct HFAToArray : ABIRewrite {
|
||||||
|
|
||||||
HFAToArray(const int max = 4) : maxFloats(max) {}
|
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());
|
Logger::println("rewriting HFA %s -> as array", dv->type->toChars());
|
||||||
LLType *t = type(dv->type);
|
LLType *t = type(dv->type);
|
||||||
return DtoLoad(DtoBitCast(DtoLVal(dv), getPtrToType(t)));
|
return DtoLoad(DtoBitCast(DtoLVal(dv), getPtrToType(t)));
|
||||||
|
@ -249,7 +237,7 @@ struct HFAToArray : ABIRewrite {
|
||||||
* Rewrite a composite as array of i64.
|
* Rewrite a composite as array of i64.
|
||||||
*/
|
*/
|
||||||
struct CompositeToArray64 : ABIRewrite {
|
struct CompositeToArray64 : ABIRewrite {
|
||||||
LLValue *put(DValue *dv) override {
|
LLValue *put(DValue *dv, bool) override {
|
||||||
Logger::println("rewriting %s -> as i64 array", dv->type->toChars());
|
Logger::println("rewriting %s -> as i64 array", dv->type->toChars());
|
||||||
LLType *t = type(dv->type);
|
LLType *t = type(dv->type);
|
||||||
return DtoLoad(DtoBitCast(DtoLVal(dv), getPtrToType(t)));
|
return DtoLoad(DtoBitCast(DtoLVal(dv), getPtrToType(t)));
|
||||||
|
@ -271,7 +259,7 @@ struct CompositeToArray64 : ABIRewrite {
|
||||||
* Rewrite a composite as array of i32.
|
* Rewrite a composite as array of i32.
|
||||||
*/
|
*/
|
||||||
struct CompositeToArray32 : ABIRewrite {
|
struct CompositeToArray32 : ABIRewrite {
|
||||||
LLValue *put(DValue *dv) override {
|
LLValue *put(DValue *dv, bool) override {
|
||||||
Logger::println("rewriting %s -> as i32 array", dv->type->toChars());
|
Logger::println("rewriting %s -> as i32 array", dv->type->toChars());
|
||||||
LLType *t = type(dv->type);
|
LLType *t = type(dv->type);
|
||||||
return DtoLoad(DtoBitCast(DtoLVal(dv), getPtrToType(t)));
|
return DtoLoad(DtoBitCast(DtoLVal(dv), getPtrToType(t)));
|
||||||
|
|
|
@ -171,7 +171,7 @@ struct RegCount {
|
||||||
* memory so that it's then readable as the other type (i.e., bit-casting).
|
* memory so that it's then readable as the other type (i.e., bit-casting).
|
||||||
*/
|
*/
|
||||||
struct X86_64_C_struct_rewrite : ABIRewrite {
|
struct X86_64_C_struct_rewrite : ABIRewrite {
|
||||||
LLValue *put(DValue *v) override {
|
LLValue *put(DValue *v, bool) override {
|
||||||
LLValue *address = getAddressOf(v);
|
LLValue *address = getAddressOf(v);
|
||||||
|
|
||||||
LLType *abiTy = getAbiType(v->type);
|
LLType *abiTy = getAbiType(v->type);
|
||||||
|
@ -196,7 +196,12 @@ struct X86_64_C_struct_rewrite : ABIRewrite {
|
||||||
* the ByVal LLVM attribute.
|
* the ByVal LLVM attribute.
|
||||||
*/
|
*/
|
||||||
struct ImplicitByvalRewrite : ABIRewrite {
|
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; }
|
LLValue *getLVal(Type *dty, LLValue *v) override { return v; }
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ struct ABIRewrite {
|
||||||
virtual ~ABIRewrite() = default;
|
virtual ~ABIRewrite() = default;
|
||||||
|
|
||||||
/// Transforms the D argument to a suitable LL argument.
|
/// 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
|
/// Transforms the LL parameter back and returns the address for the D
|
||||||
/// parameter.
|
/// parameter.
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "gen/llvmhelpers.h"
|
#include "gen/llvmhelpers.h"
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/nested.h"
|
#include "gen/nested.h"
|
||||||
|
#include "gen/optimizer.h"
|
||||||
#include "gen/rttibuilder.h"
|
#include "gen/rttibuilder.h"
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
#include "gen/structs.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) {
|
DValue *DtoCastClass(Loc &loc, DValue *val, Type *_to) {
|
||||||
IF_LOG Logger::println("DtoCastClass(%s, %s)", val->type->toChars(),
|
IF_LOG Logger::println("DtoCastClass(%s, %s)", val->type->toChars(),
|
||||||
_to->toChars());
|
_to->toChars());
|
||||||
|
|
|
@ -33,6 +33,7 @@ llvm::Constant *DtoDefineClassInfo(ClassDeclaration *cd);
|
||||||
DValue *DtoNewClass(Loc &loc, TypeClass *type, NewExp *newexp);
|
DValue *DtoNewClass(Loc &loc, TypeClass *type, NewExp *newexp);
|
||||||
void DtoInitClass(TypeClass *tc, llvm::Value *dst);
|
void DtoInitClass(TypeClass *tc, llvm::Value *dst);
|
||||||
void DtoFinalizeClass(Loc &loc, llvm::Value *inst);
|
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 *DtoCastClass(Loc &loc, DValue *val, Type *to);
|
||||||
DValue *DtoDynamicCastObject(Loc &loc, DValue *val, Type *to);
|
DValue *DtoDynamicCastObject(Loc &loc, DValue *val, Type *to);
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct DComputePointerRewrite : ABIRewrite {
|
||||||
// TODO: Is this correct?
|
// TODO: Is this correct?
|
||||||
return DtoAllocaDump(v, this->type(dty));
|
return DtoAllocaDump(v, this->type(dty));
|
||||||
}
|
}
|
||||||
LLValue *put(DValue *dv) override {
|
LLValue *put(DValue *dv, bool) override {
|
||||||
LLValue *address = getAddressOf(dv);
|
LLValue *address = getAddressOf(dv);
|
||||||
LLType *t = this->type(dv->type);
|
LLType *t = this->type(dv->type);
|
||||||
return loadFromMemory(address, t);
|
return loadFromMemory(address, t);
|
||||||
|
|
|
@ -36,9 +36,10 @@ void DComputeTarget::doCodeGen(Module *m) {
|
||||||
void DComputeTarget::emit(Module *m) {
|
void DComputeTarget::emit(Module *m) {
|
||||||
// Reset the global ABI to the target's ABI. Necessary because we have
|
// 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
|
// multiple ABI we are trying to target. Also reset gIR. These are both
|
||||||
// reused. Somewhat of a HACK.
|
// reused. MAJOR HACK.
|
||||||
gABI = abi;
|
gABI = abi;
|
||||||
gIR = _ir;
|
gIR = _ir;
|
||||||
|
gTargetMachine = targetMachine;
|
||||||
doCodeGen(m);
|
doCodeGen(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +53,6 @@ void DComputeTarget::writeModule() {
|
||||||
|
|
||||||
const char *path = FileName::combine(global.params.objdir, os.str().c_str());
|
const char *path = FileName::combine(global.params.objdir, os.str().c_str());
|
||||||
|
|
||||||
setGTargetMachine();
|
|
||||||
::writeModule(&_ir->module, path);
|
::writeModule(&_ir->module, path);
|
||||||
|
|
||||||
delete _ir;
|
delete _ir;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class Module;
|
class Module;
|
||||||
class Function;
|
class Function;
|
||||||
|
class TargetMachine;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Module;
|
class Module;
|
||||||
|
@ -32,6 +33,7 @@ public:
|
||||||
const char *short_name;
|
const char *short_name;
|
||||||
const char *binSuffix;
|
const char *binSuffix;
|
||||||
TargetABI *abi;
|
TargetABI *abi;
|
||||||
|
llvm::TargetMachine *targetMachine = nullptr;
|
||||||
// The nominal address spaces in DCompute are Private = 0, Global = 1,
|
// The nominal address spaces in DCompute are Private = 0, Global = 1,
|
||||||
// Shared = 2, Constant = 3, Generic = 4
|
// Shared = 2, Constant = 3, Generic = 4
|
||||||
std::array<int, 5> mapping;
|
std::array<int, 5> mapping;
|
||||||
|
@ -47,8 +49,6 @@ public:
|
||||||
void doCodeGen(Module *m);
|
void doCodeGen(Module *m);
|
||||||
void writeModule();
|
void writeModule();
|
||||||
|
|
||||||
// HACK: Resets the gTargetMachine to one appropriate for this dcompute target
|
|
||||||
virtual void setGTargetMachine() = 0;
|
|
||||||
virtual void addMetadata() = 0;
|
virtual void addMetadata() = 0;
|
||||||
virtual void addKernelMetadata(FuncDeclaration *df, llvm::Function *llf) = 0;
|
virtual void addKernelMetadata(FuncDeclaration *df, llvm::Function *llf) = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/optimizer.h"
|
#include "gen/optimizer.h"
|
||||||
#include "gen/to_string.h"
|
#include "gen/to_string.h"
|
||||||
|
#include "llvm/Target/TargetMachine.h"
|
||||||
#include "llvm/Transforms/Scalar.h"
|
#include "llvm/Transforms/Scalar.h"
|
||||||
#include "driver/targetmachine.h"
|
#include "driver/targetmachine.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -30,35 +31,25 @@ public:
|
||||||
// Map from nominal DCompute address space to NVPTX address space.
|
// Map from nominal DCompute address space to NVPTX address space.
|
||||||
// see $LLVM_ROOT/docs/docs/NVPTXUsage.rst section Address Spaces
|
// see $LLVM_ROOT/docs/docs/NVPTXUsage.rst section Address Spaces
|
||||||
{{5, 1, 3, 4, 0}}) {
|
{{5, 1, 3, 4, 0}}) {
|
||||||
std::string dl =
|
|
||||||
global.params.is64bit
|
const bool is64 = 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:"
|
auto tripleString = is64 ? "nvptx64-nvidia-cuda" : "nvptx-nvidia-cuda";
|
||||||
"32-"
|
|
||||||
"f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
|
targetMachine = createTargetMachine(
|
||||||
: "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:"
|
tripleString, is64 ? "nvptx64" : "nvptx",
|
||||||
"32-"
|
"sm_" + ldc::to_string(tversion / 10), {},
|
||||||
"f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64";
|
is64 ? ExplicitBitness::M64 : ExplicitBitness::M32, ::FloatABI::Hard,
|
||||||
|
llvm::Reloc::Static, llvm::CodeModel::Medium, codeGenOptLevel(), false);
|
||||||
|
|
||||||
_ir = new IRState("dcomputeTargetCUDA", ctx);
|
_ir = new IRState("dcomputeTargetCUDA", ctx);
|
||||||
_ir->module.setTargetTriple(global.params.is64bit ? "nvptx64-nvidia-cuda"
|
_ir->module.setTargetTriple(tripleString);
|
||||||
: "nvptx-nvidia-cuda");
|
_ir->module.setDataLayout(targetMachine->createDataLayout());
|
||||||
_ir->module.setDataLayout(dl);
|
|
||||||
_ir->dcomputetarget = this;
|
_ir->dcomputetarget = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMetadata() override {
|
void addMetadata() override {
|
||||||
// sm version?
|
// 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 {
|
void addKernelMetadata(FuncDeclaration *df, llvm::Function *llf) override {
|
||||||
// TODO: Handle Function attibutes
|
// TODO: Handle Function attibutes
|
||||||
|
|
|
@ -52,7 +52,6 @@ public:
|
||||||
: SPIR_DATALAYOUT32);
|
: SPIR_DATALAYOUT32);
|
||||||
_ir->dcomputetarget = this;
|
_ir->dcomputetarget = this;
|
||||||
}
|
}
|
||||||
void setGTargetMachine() override { gTargetMachine = nullptr; }
|
|
||||||
|
|
||||||
// Adapted from clang
|
// Adapted from clang
|
||||||
void addMetadata() override {
|
void addMetadata() override {
|
||||||
|
|
|
@ -26,6 +26,10 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ApiVersion = LDC_DYNAMIC_COMPILE_API_VERSION
|
||||||
|
};
|
||||||
|
|
||||||
const char *DynamicCompileModulesHeadName = "dynamiccompile_modules_head";
|
const char *DynamicCompileModulesHeadName = "dynamiccompile_modules_head";
|
||||||
|
|
||||||
llvm::GlobalValue *getPredefinedSymbol(llvm::Module &module,
|
llvm::GlobalValue *getPredefinedSymbol(llvm::Module &module,
|
||||||
|
@ -458,6 +462,7 @@ llvm::StructType *getFuncListElemType(llvm::LLVMContext &context) {
|
||||||
|
|
||||||
// struct RtCompileModuleList
|
// struct RtCompileModuleList
|
||||||
// {
|
// {
|
||||||
|
// i32 version; // Must be first
|
||||||
// RtCompileModuleList* next;
|
// RtCompileModuleList* next;
|
||||||
// i8* irData;
|
// i8* irData;
|
||||||
// i32 irDataSize;
|
// i32 irDataSize;
|
||||||
|
@ -477,6 +482,7 @@ llvm::StructType *getModuleListElemType(llvm::LLVMContext &context,
|
||||||
llvm::StructType *ret =
|
llvm::StructType *ret =
|
||||||
llvm::StructType::create(context /*, "RtCompileModuleList"*/); // fwddecl
|
llvm::StructType::create(context /*, "RtCompileModuleList"*/); // fwddecl
|
||||||
llvm::Type *elements[] = {
|
llvm::Type *elements[] = {
|
||||||
|
llvm::IntegerType::get(context, 32),
|
||||||
llvm::PointerType::getUnqual(ret),
|
llvm::PointerType::getUnqual(ret),
|
||||||
llvm::IntegerType::getInt8PtrTy(context),
|
llvm::IntegerType::getInt8PtrTy(context),
|
||||||
llvm::IntegerType::get(context, 32),
|
llvm::IntegerType::get(context, 32),
|
||||||
|
@ -579,8 +585,10 @@ llvm::GlobalVariable *generateModuleListElem(IRState *irs, const Types &types,
|
||||||
auto symListInit = generateSymList(irs, types, globalVals);
|
auto symListInit = generateSymList(irs, types, globalVals);
|
||||||
auto varlistInit = generateVarList(irs, types);
|
auto varlistInit = generateVarList(irs, types);
|
||||||
llvm::Constant *fields[] = {
|
llvm::Constant *fields[] = {
|
||||||
|
llvm::ConstantInt::get(irs->context(),
|
||||||
|
APInt(32, ApiVersion)), // version
|
||||||
llvm::ConstantPointerNull::get(llvm::dyn_cast<llvm::PointerType>(
|
llvm::ConstantPointerNull::get(llvm::dyn_cast<llvm::PointerType>(
|
||||||
elem_type->getElementType(0))), // next
|
elem_type->getElementType(1))), // next
|
||||||
irData->getInitializer(), // irdata
|
irData->getInitializer(), // irdata
|
||||||
irDataLen->getInitializer(), // irdata len
|
irDataLen->getInitializer(), // irdata len
|
||||||
funcListInit.first, // funclist
|
funcListInit.first, // funclist
|
||||||
|
@ -633,9 +641,9 @@ void generateCtorBody(IRState *irs, const Types &types, llvm::Function *func,
|
||||||
builder.SetInsertPoint(bb);
|
builder.SetInsertPoint(bb);
|
||||||
|
|
||||||
auto zero64 = llvm::ConstantInt::get(irs->context(), APInt(64, 0));
|
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);
|
auto modListHeadPtr = declareModListHead(irs->module, types);
|
||||||
llvm::Value *gepVals[] = {zero64, zero32};
|
llvm::Value *gepVals[] = {zero64, elemIndex};
|
||||||
auto elemNextPtr = builder.CreateGEP(modListElem, gepVals);
|
auto elemNextPtr = builder.CreateGEP(modListElem, gepVals);
|
||||||
auto prevHeadVal = builder.CreateLoad(builder.CreateBitOrPointerCast(
|
auto prevHeadVal = builder.CreateLoad(builder.CreateBitOrPointerCast(
|
||||||
modListHeadPtr, types.modListElemType->getPointerTo()->getPointerTo()));
|
modListHeadPtr, types.modListElemType->getPointerTo()->getPointerTo()));
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "statement.h"
|
#include "statement.h"
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
#include "driver/cl_options.h"
|
#include "driver/cl_options.h"
|
||||||
|
#include "driver/cl_options_instrumentation.h"
|
||||||
#include "driver/cl_options_sanitizers.h"
|
#include "driver/cl_options_sanitizers.h"
|
||||||
#include "gen/abi.h"
|
#include "gen/abi.h"
|
||||||
#include "gen/arrays.h"
|
#include "gen/arrays.h"
|
||||||
|
@ -463,6 +464,18 @@ void applyTargetMachineAttributes(llvm::Function &func,
|
||||||
willEliminateFramePointer() ? "false" : "true");
|
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
|
} // anonymous namespace
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1010,6 +1023,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
||||||
func->addFnAttr(LLAttribute::SanitizeThread);
|
func->addFnAttr(LLAttribute::SanitizeThread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
applyXRayAttributes(*fd, *func);
|
||||||
|
|
||||||
llvm::BasicBlock *beginbb =
|
llvm::BasicBlock *beginbb =
|
||||||
llvm::BasicBlock::Create(gIR->context(), "", func);
|
llvm::BasicBlock::Create(gIR->context(), "", func);
|
||||||
|
|
|
@ -219,12 +219,30 @@ LLValue *DtoAllocaDump(DValue *val, const char *name) {
|
||||||
return DtoAllocaDump(val, val->type, 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) {
|
LLValue *DtoAllocaDump(DValue *val, Type *asType, const char *name) {
|
||||||
return DtoAllocaDump(val, DtoType(asType), DtoAlignment(asType), name);
|
return DtoAllocaDump(val, DtoType(asType), DtoAlignment(asType), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue *DtoAllocaDump(DValue *val, LLType *asType, int alignment,
|
LLValue *DtoAllocaDump(DValue *val, LLType *asType, int alignment,
|
||||||
const char *name) {
|
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);
|
return DtoAllocaDump(DtoRVal(val), asType, alignment, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ llvm::AllocaInst *DtoRawAlloca(LLType *lltype, size_t alignment,
|
||||||
LLValue *DtoGcMalloc(Loc &loc, LLType *lltype, const char *name = "");
|
LLValue *DtoGcMalloc(Loc &loc, LLType *lltype, const char *name = "");
|
||||||
|
|
||||||
LLValue *DtoAllocaDump(DValue *val, 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, Type *asType, const char *name = "");
|
||||||
LLValue *DtoAllocaDump(DValue *val, LLType *asType, int alignment = 0,
|
LLValue *DtoAllocaDump(DValue *val, LLType *asType, int alignment = 0,
|
||||||
const char *name = "");
|
const char *name = "");
|
||||||
|
|
116
gen/tocall.cpp
116
gen/tocall.cpp
|
@ -109,8 +109,8 @@ LLFunctionType *DtoExtractFunctionType(LLType *type) {
|
||||||
|
|
||||||
static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
|
static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
|
||||||
IrFuncTy &irFty, LLFunctionType *calleeType,
|
IrFuncTy &irFty, LLFunctionType *calleeType,
|
||||||
const std::vector<DValue *> &argvals,
|
Expressions &argexps,
|
||||||
int numFormalParams) {
|
Parameters *formalParams) {
|
||||||
// Number of arguments added to the LLVM type that are implicit on the
|
// Number of arguments added to the LLVM type that are implicit on the
|
||||||
// frontend side of things (this, context pointers, etc.)
|
// frontend side of things (this, context pointers, etc.)
|
||||||
const size_t implicitLLArgCount = args.size();
|
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).
|
// Number of formal arguments in the LLVM type (i.e. excluding varargs).
|
||||||
const size_t formalLLArgCount = irFty.args.size();
|
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
|
// The number of explicit arguments in the D call expression (including
|
||||||
// varargs), not all of which necessarily generate a LLVM argument.
|
// 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
|
// construct and initialize an IrFuncTyArg object for each vararg
|
||||||
std::vector<IrFuncTyArg *> optionalIrArgs;
|
std::vector<IrFuncTyArg *> optionalIrArgs;
|
||||||
for (size_t i = numFormalParams; i < explicitDArgCount; i++) {
|
for (size_t i = formalDArgCount; i < explicitDArgCount; i++) {
|
||||||
Type *argType = argvals[i]->type;
|
Type *argType = argexps[i]->type;
|
||||||
bool passByVal = gABI->passByVal(argType);
|
bool passByVal = gABI->passByVal(argType);
|
||||||
|
|
||||||
AttrBuilder initialAttrs;
|
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,
|
// 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.
|
// which is the reverse of the LLVM order if irFty.reverseParams is true.
|
||||||
for (size_t i = 0; i < explicitLLArgCount; ++i) {
|
size_t dArgIndex = 0;
|
||||||
const bool isVararg = (i >= irFty.args.size());
|
for (size_t i = 0; i < explicitLLArgCount; ++i, ++dArgIndex) {
|
||||||
|
const bool isVararg = (i >= formalLLArgCount);
|
||||||
IrFuncTyArg *irArg = nullptr;
|
IrFuncTyArg *irArg = nullptr;
|
||||||
if (isVararg) {
|
if (isVararg) {
|
||||||
irArg = optionalIrArgs[i - numFormalParams];
|
irArg = optionalIrArgs[i - formalLLArgCount];
|
||||||
} else {
|
} else {
|
||||||
irArg = irFty.args[i];
|
irArg = irFty.args[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
DValue *const argval = argvals[irArg->parametersIdx];
|
// Make sure to evaluate argument expressions for which there's no LL
|
||||||
Type *const argType = argval->type;
|
// parameter (e.g., empty structs for some ABIs).
|
||||||
|
for (; dArgIndex < irArg->parametersIdx; ++dArgIndex) {
|
||||||
llvm::Value *llVal = nullptr;
|
toElem(argexps[dArgIndex]);
|
||||||
if (isVararg) {
|
|
||||||
llVal = irFty.putParam(*irArg, argval);
|
|
||||||
} else {
|
|
||||||
llVal = irFty.putParam(i, argval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 =
|
const size_t llArgIdx =
|
||||||
implicitLLArgCount +
|
implicitLLArgCount +
|
||||||
(irFty.reverseParams ? explicitLLArgCount - i - 1 : i);
|
(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:
|
// Hack around LDC assuming structs and static arrays are in memory:
|
||||||
// If the function wants a struct, and the argument value is a
|
// If the function wants a struct, and the argument value is a
|
||||||
// pointer to a struct, load from it before passing it in.
|
// 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 && !isaPointer(paramType)) ||
|
||||||
(isVararg && !irArg->byref && !irArg->isByVal()))) {
|
(isVararg && !irArg->byref && !irArg->isByVal()))) {
|
||||||
Logger::println("Loading struct type for function argument");
|
Logger::println("Loading struct type for function argument");
|
||||||
|
@ -203,12 +218,15 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
|
||||||
delete irArg;
|
delete irArg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (; dArgIndex < explicitDArgCount; ++dArgIndex) {
|
||||||
|
toElem(argexps[dArgIndex]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static LLValue *
|
static LLValue *getTypeinfoArrayArgumentForDVarArg(Expressions *argexps,
|
||||||
getTypeinfoArrayArgumentForDVarArg(const std::vector<DValue *> &argvals,
|
|
||||||
int begin) {
|
int begin) {
|
||||||
IF_LOG Logger::println("doing d-style variadic arguments");
|
IF_LOG Logger::println("doing d-style variadic arguments");
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
|
@ -216,7 +234,8 @@ getTypeinfoArrayArgumentForDVarArg(const std::vector<DValue *> &argvals,
|
||||||
// number of non variadic args
|
// number of non variadic args
|
||||||
IF_LOG Logger::println("num non vararg params = %d", begin);
|
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
|
// build type info array
|
||||||
LLType *typeinfotype = DtoType(Type::dtypeinfo->type);
|
LLType *typeinfotype = DtoType(Type::dtypeinfo->type);
|
||||||
|
@ -229,9 +248,9 @@ getTypeinfoArrayArgumentForDVarArg(const std::vector<DValue *> &argvals,
|
||||||
IF_LOG Logger::cout() << "_arguments storage: " << *typeinfomem << '\n';
|
IF_LOG Logger::cout() << "_arguments storage: " << *typeinfomem << '\n';
|
||||||
|
|
||||||
std::vector<LLConstant *> vtypeinfos;
|
std::vector<LLConstant *> vtypeinfos;
|
||||||
vtypeinfos.reserve(argvals.size());
|
vtypeinfos.reserve(numVariadicArgs);
|
||||||
for (size_t i = begin; i < argvals.size(); i++) {
|
for (size_t i = begin; i < numArgExps; i++) {
|
||||||
vtypeinfos.push_back(DtoTypeInfoOf(argvals[i]->type));
|
vtypeinfos.push_back(DtoTypeInfoOf((*argexps)[i]->type));
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply initializer
|
// apply initializer
|
||||||
|
@ -636,10 +655,9 @@ class ImplicitArgumentsBuilder {
|
||||||
public:
|
public:
|
||||||
ImplicitArgumentsBuilder(std::vector<LLValue *> &args, AttrSet &attrs,
|
ImplicitArgumentsBuilder(std::vector<LLValue *> &args, AttrSet &attrs,
|
||||||
Loc &loc, DValue *fnval,
|
Loc &loc, DValue *fnval,
|
||||||
LLFunctionType *llCalleeType,
|
LLFunctionType *llCalleeType, Expressions *argexps,
|
||||||
const std::vector<DValue *> &argvals,
|
|
||||||
Type *resulttype, LLValue *sretPointer)
|
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),
|
resulttype(resulttype), sretPointer(sretPointer),
|
||||||
// computed:
|
// computed:
|
||||||
isDelegateCall(fnval->type->toBasetype()->ty == Tdelegate),
|
isDelegateCall(fnval->type->toBasetype()->ty == Tdelegate),
|
||||||
|
@ -665,7 +683,7 @@ private:
|
||||||
AttrSet &attrs;
|
AttrSet &attrs;
|
||||||
Loc &loc;
|
Loc &loc;
|
||||||
DValue *const fnval;
|
DValue *const fnval;
|
||||||
const std::vector<DValue *> &argvals;
|
Expressions *const argexps;
|
||||||
Type *const resulttype;
|
Type *const resulttype;
|
||||||
LLValue *const sretPointer;
|
LLValue *const sretPointer;
|
||||||
|
|
||||||
|
@ -786,7 +804,7 @@ private:
|
||||||
|
|
||||||
int numFormalParams = Parameter::dim(tf->parameters);
|
int numFormalParams = Parameter::dim(tf->parameters);
|
||||||
LLValue *argumentsArg =
|
LLValue *argumentsArg =
|
||||||
getTypeinfoArrayArgumentForDVarArg(argvals, numFormalParams);
|
getTypeinfoArrayArgumentForDVarArg(argexps, numFormalParams);
|
||||||
|
|
||||||
args.push_back(argumentsArg);
|
args.push_back(argumentsArg);
|
||||||
attrs.addToParam(args.size() - 1, irFty.arg_arguments->attrs);
|
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 !
|
// FIXME: this function is a mess !
|
||||||
DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
|
DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
|
||||||
Expressions *arguments, LLValue *sretPointer) {
|
Expressions *arguments, LLValue *sretPointer) {
|
||||||
IF_LOG Logger::println("DtoCallFunction()");
|
IF_LOG Logger::println("DtoCallFunction()");
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
|
|
||||||
const auto argvals = evaluateArgExpressions(fnval, arguments);
|
|
||||||
|
|
||||||
// make sure the D callee type has been processed
|
// make sure the D callee type has been processed
|
||||||
DtoType(fnval->type);
|
DtoType(fnval->type);
|
||||||
|
|
||||||
|
@ -871,7 +856,7 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
|
||||||
args.reserve(irFty.args.size());
|
args.reserve(irFty.args.size());
|
||||||
|
|
||||||
// handle implicit arguments (sret, context/this, _arguments)
|
// 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);
|
resulttype, sretPointer);
|
||||||
iab.addImplicitArgs();
|
iab.addImplicitArgs();
|
||||||
|
|
||||||
|
@ -889,9 +874,10 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
|
||||||
// Logger::cout() << "LLVM functype: " << *callable->getType() << '\n';
|
// Logger::cout() << "LLVM functype: " << *callable->getType() << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
const int numFormalParams = Parameter::dim(tf->parameters); // excl. variadics
|
if (arguments) {
|
||||||
addExplicitArguments(args, attrs, irFty, callableTy, argvals,
|
addExplicitArguments(args, attrs, irFty, callableTy, *arguments,
|
||||||
numFormalParams);
|
tf->parameters);
|
||||||
|
}
|
||||||
|
|
||||||
if (irFty.arg_objcSelector) {
|
if (irFty.arg_objcSelector) {
|
||||||
// Use runtime msgSend function bitcasted as original call
|
// Use runtime msgSend function bitcasted as original call
|
||||||
|
|
10
gen/toir.cpp
10
gen/toir.cpp
|
@ -239,15 +239,9 @@ public:
|
||||||
// adding more control flow.
|
// adding more control flow.
|
||||||
if (result && result->type->ty != Tvoid &&
|
if (result && result->type->ty != Tvoid &&
|
||||||
!result->definedInFuncEntryBB()) {
|
!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);
|
LLValue *copy = DtoAllocaDump(result);
|
||||||
result = new DLValue(result->type, copy);
|
result = new DLValue(result->type, copy);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
llvm::BasicBlock *endbb = p->insertBB("toElem.success");
|
llvm::BasicBlock *endbb = p->insertBB("toElem.success");
|
||||||
p->funcGen().scopes.runCleanups(initialCleanupScope, endbb);
|
p->funcGen().scopes.runCleanups(initialCleanupScope, endbb);
|
||||||
|
@ -1616,7 +1610,9 @@ public:
|
||||||
} else if (e->e1->op == TOKvar) {
|
} else if (e->e1->op == TOKvar) {
|
||||||
if (auto vd = static_cast<VarExp *>(e->e1)->var->isVarDeclaration()) {
|
if (auto vd = static_cast<VarExp *>(e->e1)->var->isVarDeclaration()) {
|
||||||
if (vd->onstack) {
|
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;
|
onstack = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,6 @@ llvm::GetElementPtrInst *DtoGEP(LLValue *ptr, llvm::ArrayRef<LLValue *> indices,
|
||||||
bool inBounds, const char *name,
|
bool inBounds, const char *name,
|
||||||
llvm::BasicBlock *bb) {
|
llvm::BasicBlock *bb) {
|
||||||
LLPointerType *p = isaPointer(ptr);
|
LLPointerType *p = isaPointer(ptr);
|
||||||
(void)p;
|
|
||||||
assert(p && "GEP expects a pointer type");
|
assert(p && "GEP expects a pointer type");
|
||||||
auto gep = llvm::GetElementPtrInst::Create(
|
auto gep = llvm::GetElementPtrInst::Create(
|
||||||
p->getElementType(), ptr, indices, name, bb ? bb : gIR->scopebb());
|
p->getElementType(), ptr, indices, name, bb ? bb : gIR->scopebb());
|
||||||
|
|
|
@ -33,7 +33,7 @@ llvm::Value *IrFuncTy::putRet(DValue *dval) {
|
||||||
if (ret->rewrite) {
|
if (ret->rewrite) {
|
||||||
Logger::println("Rewrite: putRet");
|
Logger::println("Rewrite: putRet");
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
return ret->rewrite->put(dval);
|
return ret->rewrite->put(dval, /*isModifiableLvalue=*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret->byref || DtoIsInMemoryOnly(dval->type))
|
if (ret->byref || DtoIsInMemoryOnly(dval->type))
|
||||||
|
@ -66,20 +66,20 @@ llvm::Value *IrFuncTy::getRetLVal(Type *dty, LLValue *val) {
|
||||||
return DtoAllocaDump(val, dty);
|
return DtoAllocaDump(val, dty);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value *IrFuncTy::putParam(size_t idx, DValue *dval) {
|
llvm::Value *IrFuncTy::putParam(const IrFuncTyArg &arg, DValue *dval,
|
||||||
assert(idx < args.size() && "invalid putParam");
|
bool isModifiableLvalue) {
|
||||||
return putParam(*args[idx], dval);
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *IrFuncTy::putParam(const IrFuncTyArg &arg, DValue *dval) {
|
|
||||||
if (arg.rewrite) {
|
if (arg.rewrite) {
|
||||||
Logger::println("Rewrite: putParam");
|
Logger::println("Rewrite: putParam");
|
||||||
LOG_SCOPE
|
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 DtoLVal(dval);
|
||||||
|
}
|
||||||
|
|
||||||
return DtoRVal(dval);
|
return DtoRVal(dval);
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,8 +111,8 @@ struct IrFuncTy {
|
||||||
llvm::Value *getRetRVal(Type *dty, llvm::Value *val);
|
llvm::Value *getRetRVal(Type *dty, llvm::Value *val);
|
||||||
llvm::Value *getRetLVal(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);
|
llvm::Value *getParamLVal(Type *dty, size_t idx, llvm::Value *val);
|
||||||
|
|
||||||
AttrSet getParamAttrs(bool passThisBeforeSret);
|
AttrSet getParamAttrs(bool passThisBeforeSret);
|
||||||
|
|
|
@ -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})
|
build_runtime_variants("${d_flags}" "${c_flags}" "${ld_flags}" "${path_suffix}" ${outlist_targets})
|
||||||
|
|
||||||
# static profile-rt
|
# 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)
|
get_target_suffix("" "${path_suffix}" target_suffix)
|
||||||
set_common_library_properties(ldc-profile-rt${target_suffix} OFF)
|
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -70,15 +70,16 @@ struct RtCompileVarList {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RtCompileModuleList {
|
struct RtCompileModuleList {
|
||||||
|
int32_t version;
|
||||||
RtCompileModuleList *next;
|
RtCompileModuleList *next;
|
||||||
const char *irData;
|
const char *irData;
|
||||||
int irDataSize;
|
int32_t irDataSize;
|
||||||
const RtCompileFuncList *funcList;
|
const RtCompileFuncList *funcList;
|
||||||
int funcListSize;
|
int32_t funcListSize;
|
||||||
const RtCompileSymList *symList;
|
const RtCompileSymList *symList;
|
||||||
int symListSize;
|
int32_t symListSize;
|
||||||
const RtCompileVarList *varList;
|
const RtCompileVarList *varList;
|
||||||
int varListSize;
|
int32_t varListSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
@ -347,9 +348,15 @@ struct JitFinaliser final {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename F>
|
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;
|
auto current = modlist_head;
|
||||||
while (current != nullptr) {
|
while (current != nullptr) {
|
||||||
|
interruptPoint(context, "check version");
|
||||||
|
if (current->version != ApiVersion) {
|
||||||
|
fatal(context, "Module was built with different jit api version");
|
||||||
|
}
|
||||||
fun(*current);
|
fun(*current);
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
@ -370,7 +377,7 @@ void rtCompileProcessImplSoInternal(const RtCompileModuleList *modlist_head,
|
||||||
OptimizerSettings settings;
|
OptimizerSettings settings;
|
||||||
settings.optLevel = context.optLevel;
|
settings.optLevel = context.optLevel;
|
||||||
settings.sizeLevel = context.sizeLevel;
|
settings.sizeLevel = context.sizeLevel;
|
||||||
enumModules(modlist_head, [&](const RtCompileModuleList ¤t) {
|
enumModules(modlist_head, context, [&](const RtCompileModuleList ¤t) {
|
||||||
interruptPoint(context, "load IR");
|
interruptPoint(context, "load IR");
|
||||||
auto buff = llvm::MemoryBuffer::getMemBuffer(
|
auto buff = llvm::MemoryBuffer::getMemBuffer(
|
||||||
llvm::StringRef(current.irData,
|
llvm::StringRef(current.irData,
|
||||||
|
@ -476,7 +483,7 @@ __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
__attribute__ ((visibility ("default")))
|
__attribute__ ((visibility ("default")))
|
||||||
#endif
|
#endif
|
||||||
void rtCompileProcessImplSo(const void *modlist_head,
|
void JIT_API_ENTRYPOINT(const void *modlist_head,
|
||||||
const Context *context, size_t contextSize) {
|
const Context *context, size_t contextSize) {
|
||||||
assert(nullptr != context);
|
assert(nullptr != context);
|
||||||
assert(sizeof(*context) == contextSize);
|
assert(sizeof(*context) == contextSize);
|
||||||
|
|
|
@ -23,6 +23,16 @@ enum class DumpStage : int {
|
||||||
FinalAsm = 3
|
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,
|
typedef void (*InterruptPointHandlerT)(void *, const char *action,
|
||||||
const char *object);
|
const char *object);
|
||||||
typedef void (*FatalHandlerT)(void *, const char *reason);
|
typedef void (*FatalHandlerT)(void *, const char *reason);
|
||||||
|
|
|
@ -266,7 +266,7 @@ void disassemble(const llvm::TargetMachine &tm,
|
||||||
|
|
||||||
llvm::MCTargetOptions opts;
|
llvm::MCTargetOptions opts;
|
||||||
auto mab = unique(target.createMCAsmBackend(
|
auto mab = unique(target.createMCAsmBackend(
|
||||||
#if LDC_LLVM_VER >= 700
|
#if LDC_LLVM_VER >= 600
|
||||||
*sti, *mri, opts)
|
*sti, *mri, opts)
|
||||||
#else
|
#else
|
||||||
*mri, tm.getTargetTriple().getTriple(), tm.getTargetCPU(), opts)
|
*mri, tm.getTargetTriple().getTriple(), tm.getTargetCPU(), opts)
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
|
|
||||||
struct Context;
|
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" {
|
extern "C" {
|
||||||
|
|
||||||
// Silence missing-variable-declaration clang warning
|
// Silence missing-variable-declaration clang warning
|
||||||
|
@ -25,11 +31,11 @@ const void *dynamiccompile_modules_head = nullptr;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
__declspec(dllimport)
|
__declspec(dllimport)
|
||||||
#endif
|
#endif
|
||||||
extern void rtCompileProcessImplSo(const void *modlist_head,
|
extern void JIT_API_ENTRYPOINT(const void *modlist_head,
|
||||||
const Context *context,
|
const Context *context,
|
||||||
std::size_t contextSize);
|
std::size_t contextSize);
|
||||||
|
|
||||||
void rtCompileProcessImpl(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
# Add LLVM Profile runtime for PGO
|
# 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
|
# Choose the correct subfolder depending on the LLVM version
|
||||||
set(PROFILERT_LIBSRC_DIR "${PROFILERT_DIR}/profile-rt-${LLVM_VERSION_MAJOR}${LLVM_VERSION_MINOR}")
|
set(PROFILERT_LIBSRC_DIR "${PROFILERT_DIR}/profile-rt-${LLVM_VERSION_MAJOR}${LLVM_VERSION_MINOR}")
|
||||||
file(GLOB LDC_PROFRT_C ${PROFILERT_LIBSRC_DIR}/*.c)
|
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")
|
set(PROFRT_EXTRA_FLAGS "${PROFRT_EXTRA_FLAGS} -DCOMPILER_RT_HAS_UNAME=1")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Sets up the targets for building the D-source profile-rt object files,
|
macro(build_profile_runtime c_flags ld_flags lib_suffix path_suffix outlist_targets)
|
||||||
# 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)
|
|
||||||
set(output_path ${CMAKE_BINARY_DIR}/lib${path_suffix})
|
set(output_path ${CMAKE_BINARY_DIR}/lib${path_suffix})
|
||||||
|
|
||||||
set(profilert_d_o "")
|
get_target_suffix("${lib_suffix}" "${path_suffix}" target_suffix)
|
||||||
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)
|
|
||||||
|
|
||||||
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(
|
set_target_properties(
|
||||||
ldc-profile-rt${target_suffix} PROPERTIES
|
ldc-profile-rt${target_suffix} PROPERTIES
|
||||||
OUTPUT_NAME ldc-profile-rt${lib_suffix}
|
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()
|
endmacro()
|
||||||
|
|
||||||
# Install D interface files to profile-rt.
|
# 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")
|
||||||
|
|
|
@ -3,11 +3,16 @@
|
||||||
* instrumented programs (compiled with -fprofile-instr-generate).
|
* instrumented programs (compiled with -fprofile-instr-generate).
|
||||||
* It provides an interface to the profile-rt runtime library.
|
* 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
|
* This module is template-only, and is not compiled nor linked into druntime.
|
||||||
* License: University of Illinois Open Source License and MIT License. See LDC's LICENSE for details.
|
* This way, LDC does not need its own profile-rt library and LDC can directly
|
||||||
* Authors: Johan B C Engelen
|
* 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;
|
module ldc.profile;
|
||||||
|
|
||||||
|
@ -101,7 +106,6 @@ extern(C++) struct ProfileData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symbols provided by profile-rt lib
|
// Symbols provided by profile-rt lib
|
||||||
private {
|
|
||||||
extern(C) {
|
extern(C) {
|
||||||
alias uint64_t = ulong;
|
alias uint64_t = ulong;
|
||||||
alias __llvm_profile_data = ProfileData;
|
alias __llvm_profile_data = ProfileData;
|
||||||
|
@ -115,16 +119,14 @@ extern(C) {
|
||||||
void __llvm_profile_reset_counters();
|
void __llvm_profile_reset_counters();
|
||||||
uint64_t __llvm_profile_get_magic();
|
uint64_t __llvm_profile_get_magic();
|
||||||
uint64_t __llvm_profile_get_version();
|
uint64_t __llvm_profile_get_version();
|
||||||
}}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset all profiling information of the whole program.
|
* Reset all profiling information of the whole program.
|
||||||
* This can be used for example to remove transient start-up behavior from the
|
* This can be used for example to remove transient start-up behavior from the
|
||||||
* profile.
|
* profile.
|
||||||
*/
|
*/
|
||||||
void resetAll() {
|
alias resetAll = __llvm_profile_reset_counters;
|
||||||
__llvm_profile_reset_counters();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset profile counter values for a function.
|
* Reset profile counter values for a function.
|
47
tests/codegen/call_args_evalorder.d
Normal file
47
tests/codegen/call_args_evalorder.d
Normal 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
81
tests/codegen/gh2515.d
Normal 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
|
||||||
|
}
|
10
tests/instrument/lit.local.cfg
Normal file
10
tests/instrument/lit.local.cfg
Normal 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
|
11
tests/instrument/xray_check_pipeline.d
Normal file
11
tests/instrument/xray_check_pipeline.d
Normal 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()
|
||||||
|
{
|
||||||
|
}
|
21
tests/instrument/xray_instrument.d
Normal file
21
tests/instrument/xray_instrument.d
Normal 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"
|
11
tests/instrument/xray_instrument_threshold.d
Normal file
11
tests/instrument/xray_instrument_threshold.d
Normal 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"
|
15
tests/instrument/xray_link.d
Normal file
15
tests/instrument/xray_link.d
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue