mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-05 17:43:35 +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)
|
||||
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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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@";
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -52,7 +52,6 @@ public:
|
|||
: SPIR_DATALAYOUT32);
|
||||
_ir->dcomputetarget = this;
|
||||
}
|
||||
void setGTargetMachine() override { gTargetMachine = nullptr; }
|
||||
|
||||
// Adapted from clang
|
||||
void addMetadata() override {
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = "");
|
||||
|
|
118
gen/tocall.cpp
118
gen/tocall.cpp
|
@ -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,20 +218,24 @@ 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,
|
||||
int begin) {
|
||||
static LLValue *getTypeinfoArrayArgumentForDVarArg(Expressions *argexps,
|
||||
int begin) {
|
||||
IF_LOG Logger::println("doing d-style variadic arguments");
|
||||
LOG_SCOPE
|
||||
|
||||
// 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
|
||||
|
|
14
gen/toir.cpp
14
gen/toir.cpp
|
@ -239,14 +239,8 @@ 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);
|
||||
}
|
||||
LLValue *copy = DtoAllocaDump(result);
|
||||
result = new DLValue(result->type, copy);
|
||||
}
|
||||
|
||||
llvm::BasicBlock *endbb = p->insertBB("toElem.success");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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 ¤t) {
|
||||
enumModules(modlist_head, context, [&](const RtCompileModuleList ¤t) {
|
||||
interruptPoint(context, "load IR");
|
||||
auto buff = llvm::MemoryBuffer::getMemBuffer(
|
||||
llvm::StringRef(current.irData,
|
||||
|
@ -476,8 +483,8 @@ __declspec(dllexport)
|
|||
#else
|
||||
__attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
void rtCompileProcessImplSo(const void *modlist_head,
|
||||
const Context *context, size_t contextSize) {
|
||||
void JIT_API_ENTRYPOINT(const void *modlist_head,
|
||||
const Context *context, size_t contextSize) {
|
||||
assert(nullptr != context);
|
||||
assert(sizeof(*context) == contextSize);
|
||||
rtCompileProcessImplSoInternal(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
const Context *context,
|
||||
std::size_t contextSize);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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.
|
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