mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-29 14:40:40 +03:00
Merge branch 'master' into merge-2.069
This commit is contained in:
commit
acdcc4a8c1
28 changed files with 600 additions and 277 deletions
|
@ -33,6 +33,8 @@ addons:
|
||||||
- llvm-3.7-dev
|
- llvm-3.7-dev
|
||||||
- llvm-3.8
|
- llvm-3.8
|
||||||
- llvm-3.8-dev
|
- llvm-3.8-dev
|
||||||
|
- llvm-3.9
|
||||||
|
- llvm-3.9-dev
|
||||||
install:
|
install:
|
||||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then export CC="gcc-4.9"; export CXX="g++-4.9"; fi
|
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then export CC="gcc-4.9"; export CXX="g++-4.9"; fi
|
||||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew update; brew install llvm36; brew install libconfig; fi;
|
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew update; brew install llvm36; brew install libconfig; fi;
|
||||||
|
@ -45,14 +47,13 @@ env:
|
||||||
- LLVM_CONFIG="llvm-config-3.6" OPTS="-DBUILD_SHARED_LIBS=ON"
|
- LLVM_CONFIG="llvm-config-3.6" OPTS="-DBUILD_SHARED_LIBS=ON"
|
||||||
- LLVM_CONFIG="llvm-config-3.5" OPTS="-DTEST_COVERAGE=ON"
|
- LLVM_CONFIG="llvm-config-3.5" OPTS="-DTEST_COVERAGE=ON"
|
||||||
- LLVM_CONFIG="llvm-config-3.8"
|
- LLVM_CONFIG="llvm-config-3.8"
|
||||||
|
- LLVM_CONFIG="llvm-config-3.9"
|
||||||
# OSX only (and the only ones for OSX):
|
# OSX only (and the only ones for OSX):
|
||||||
- LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Debug"
|
- LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Debug"
|
||||||
- LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Release"
|
- LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Release"
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- env: LLVM_CONFIG="llvm-config-3.8"
|
- env: LLVM_CONFIG="llvm-config-3.9"
|
||||||
- os: osx
|
|
||||||
env: LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Release"
|
|
||||||
exclude:
|
exclude:
|
||||||
- os: linux
|
- os: linux
|
||||||
env: LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Debug"
|
env: LLVM_CONFIG="llvm-config-3.6" TEST_CONFIG="Debug"
|
||||||
|
@ -66,6 +67,8 @@ matrix:
|
||||||
env: LLVM_CONFIG="llvm-config-3.5" OPTS="-DTEST_COVERAGE=ON"
|
env: LLVM_CONFIG="llvm-config-3.5" OPTS="-DTEST_COVERAGE=ON"
|
||||||
- os: osx
|
- os: osx
|
||||||
env: LLVM_CONFIG="llvm-config-3.8"
|
env: LLVM_CONFIG="llvm-config-3.8"
|
||||||
|
- os: osx
|
||||||
|
env: LLVM_CONFIG="llvm-config-3.9"
|
||||||
script:
|
script:
|
||||||
- cmake -DLLVM_CONFIG=$(which ${LLVM_CONFIG}) $OPTS .
|
- cmake -DLLVM_CONFIG=$(which ${LLVM_CONFIG}) $OPTS .
|
||||||
- make -j3
|
- make -j3
|
||||||
|
|
|
@ -17,7 +17,7 @@ include(CheckCXXCompilerFlag)
|
||||||
#
|
#
|
||||||
|
|
||||||
find_package(LLVM 3.5 REQUIRED
|
find_package(LLVM 3.5 REQUIRED
|
||||||
all-targets analysis asmparser asmprinter bitreader bitwriter codegen core debuginfodwarf instcombine ipa ipo instrumentation irreader linker lto mc mcdisassembler mcparser objcarcopts object option profiledata scalaropts selectiondag support tablegen target transformutils vectorize ${EXTRA_LLVM_MODULES})
|
all-targets analysis asmparser asmprinter bitreader bitwriter codegen core debuginfocodeview debuginfodwarf debuginfopdb instcombine ipa ipo instrumentation irreader linker lto mc mcdisassembler mcparser objcarcopts object option profiledata scalaropts selectiondag support tablegen target transformutils vectorize ${EXTRA_LLVM_MODULES})
|
||||||
math(EXPR LDC_LLVM_VER ${LLVM_VERSION_MAJOR}*100+${LLVM_VERSION_MINOR})
|
math(EXPR LDC_LLVM_VER ${LLVM_VERSION_MAJOR}*100+${LLVM_VERSION_MINOR})
|
||||||
# Remove LLVMTableGen library from list of libraries
|
# Remove LLVMTableGen library from list of libraries
|
||||||
string(REGEX MATCH "^-.*LLVMTableGen[^;]*;|;-.*LLVMTableGen[^;]*" LLVM_TABLEGEN_LIBRARY "${LLVM_LIBRARIES}")
|
string(REGEX MATCH "^-.*LLVMTableGen[^;]*;|;-.*LLVMTableGen[^;]*" LLVM_TABLEGEN_LIBRARY "${LLVM_LIBRARIES}")
|
||||||
|
@ -252,6 +252,8 @@ string(REPLACE "-Werror " "" LLVM_CXXFLAGS ${LLVM_CXXFLAGS})
|
||||||
if (UNIX AND NOT "${LLVM_LDFLAGS}" STREQUAL "")
|
if (UNIX AND NOT "${LLVM_LDFLAGS}" STREQUAL "")
|
||||||
# LLVM_LDFLAGS may contain -l-lld which is a wrong library reference (AIX)
|
# LLVM_LDFLAGS may contain -l-lld which is a wrong library reference (AIX)
|
||||||
string(REPLACE "-l-lld " "-lld " LLVM_LDFLAGS ${LLVM_LDFLAGS})
|
string(REPLACE "-l-lld " "-lld " LLVM_LDFLAGS ${LLVM_LDFLAGS})
|
||||||
|
# LLVM_LDFLAGS may have a space at the end
|
||||||
|
string(REGEX REPLACE " $" "" LLVM_LDFLAGS ${LLVM_LDFLAGS})
|
||||||
endif()
|
endif()
|
||||||
# LLVM_CXXFLAGS may contain -Wcovered-switch-default and -fcolor-diagnostics
|
# LLVM_CXXFLAGS may contain -Wcovered-switch-default and -fcolor-diagnostics
|
||||||
# which are clang-only options
|
# which are clang-only options
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
# We also want an user-specified LLVM_ROOT_DIR to take precedence over the
|
# We also want an user-specified LLVM_ROOT_DIR to take precedence over the
|
||||||
# system default locations such as /usr/local/bin. Executing find_program()
|
# system default locations such as /usr/local/bin. Executing find_program()
|
||||||
# multiples times is the approach recommended in the docs.
|
# multiples times is the approach recommended in the docs.
|
||||||
set(llvm_config_names llvm-config-3.8 llvm-config38
|
set(llvm_config_names llvm-config-3.9 llvm-config39
|
||||||
|
llvm-config-3.8 llvm-config38
|
||||||
llvm-config-3.7 llvm-config37
|
llvm-config-3.7 llvm-config37
|
||||||
llvm-config-3.6 llvm-config36
|
llvm-config-3.6 llvm-config36
|
||||||
llvm-config-3.5 llvm-config35
|
llvm-config-3.5 llvm-config35
|
||||||
|
@ -67,23 +68,17 @@ if ((WIN32 AND NOT(MINGW OR CYGWIN)) OR NOT LLVM_CONFIG)
|
||||||
if(TARGET_AArch64 GREATER -1)
|
if(TARGET_AArch64 GREATER -1)
|
||||||
list(APPEND LLVM_FIND_COMPONENTS AArch64Utils)
|
list(APPEND LLVM_FIND_COMPONENTS AArch64Utils)
|
||||||
endif()
|
endif()
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "backend" index)
|
|
||||||
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-2][\\.0-9A-Za-z]*")
|
|
||||||
# Versions below 3.3 do not support components objcarcopts, option
|
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "objcarcopts" index)
|
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "option" index)
|
|
||||||
endif()
|
|
||||||
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-4][\\.0-9A-Za-z]*")
|
|
||||||
# Versions below 3.5 do not support components lto, profiledata
|
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "lto" index)
|
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "profiledata" index)
|
|
||||||
endif()
|
|
||||||
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-6][\\.0-9A-Za-z]*")
|
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-6][\\.0-9A-Za-z]*")
|
||||||
# Versions below 3.7 do not support components debuginfodwarf
|
# Versions below 3.7 do not support components debuginfo[dwarf|pdb]
|
||||||
# Only debuginfo is available
|
# Only debuginfo is available
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfodwarf" index)
|
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfodwarf" index)
|
||||||
|
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfopdb" index)
|
||||||
list(APPEND LLVM_FIND_COMPONENTS "debuginfo")
|
list(APPEND LLVM_FIND_COMPONENTS "debuginfo")
|
||||||
endif()
|
endif()
|
||||||
|
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-8][\\.0-9A-Za-z]*")
|
||||||
|
# Versions below 3.9 do not support components debuginfocodeview
|
||||||
|
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfocodeview" index)
|
||||||
|
endif()
|
||||||
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[8-9][\\.0-9A-Za-z]*")
|
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[8-9][\\.0-9A-Za-z]*")
|
||||||
# Versions beginning with 3.8 do not support component ipa
|
# Versions beginning with 3.8 do not support component ipa
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "ipa" index)
|
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "ipa" index)
|
||||||
|
@ -150,23 +145,19 @@ else()
|
||||||
llvm_set(HOST_TARGET host-target)
|
llvm_set(HOST_TARGET host-target)
|
||||||
llvm_set(INCLUDE_DIRS includedir true)
|
llvm_set(INCLUDE_DIRS includedir true)
|
||||||
llvm_set(ROOT_DIR prefix true)
|
llvm_set(ROOT_DIR prefix true)
|
||||||
|
llvm_set(ENABLE_ASSERTIONS assertion-mode)
|
||||||
|
|
||||||
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-2][\\.0-9A-Za-z]*")
|
|
||||||
# Versions below 3.3 do not support components objcarcopts, option
|
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "objcarcopts" index)
|
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "option" index)
|
|
||||||
endif()
|
|
||||||
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-4][\\.0-9A-Za-z]*")
|
|
||||||
# Versions below 3.5 do not support components lto, profiledata
|
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "lto" index)
|
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "profiledata" index)
|
|
||||||
endif()
|
|
||||||
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-6][\\.0-9A-Za-z]*")
|
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-6][\\.0-9A-Za-z]*")
|
||||||
# Versions below 3.7 do not support components debuginfodwarf
|
# Versions below 3.7 do not support components debuginfo[dwarf|pdb]
|
||||||
# Only debuginfo is available
|
# Only debuginfo is available
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfodwarf" index)
|
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfodwarf" index)
|
||||||
|
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfopdb" index)
|
||||||
list(APPEND LLVM_FIND_COMPONENTS "debuginfo")
|
list(APPEND LLVM_FIND_COMPONENTS "debuginfo")
|
||||||
endif()
|
endif()
|
||||||
|
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-8][\\.0-9A-Za-z]*")
|
||||||
|
# Versions below 3.9 do not support components debuginfocodeview
|
||||||
|
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfocodeview" index)
|
||||||
|
endif()
|
||||||
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[8-9][\\.0-9A-Za-z]*")
|
if(${LLVM_VERSION_STRING} MATCHES "^3\\.[8-9][\\.0-9A-Za-z]*")
|
||||||
# Versions beginning with 3.8 do not support component ipa
|
# Versions beginning with 3.8 do not support component ipa
|
||||||
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "ipa" index)
|
list(REMOVE_ITEM LLVM_FIND_COMPONENTS "ipa" index)
|
||||||
|
@ -181,6 +172,8 @@ else()
|
||||||
endif()
|
endif()
|
||||||
llvm_set(LIBRARY_DIRS libdir true)
|
llvm_set(LIBRARY_DIRS libdir true)
|
||||||
llvm_set_libs(LIBRARIES libs)
|
llvm_set_libs(LIBRARIES libs)
|
||||||
|
llvm_set(TARGETS_TO_BUILD targets-built)
|
||||||
|
string(REGEX MATCHALL "${pattern}[^ ]+" LLVM_TARGETS_TO_BUILD ${LLVM_TARGETS_TO_BUILD})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# On CMake builds of LLVM, the output of llvm-config --cxxflags does not
|
# On CMake builds of LLVM, the output of llvm-config --cxxflags does not
|
||||||
|
|
|
@ -651,7 +651,7 @@ longdouble Port::strtold(const char *p, char **endp)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__ || __HAIKU__
|
#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__ || __HAIKU__
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#if __linux__
|
#if __linux__
|
||||||
|
@ -806,7 +806,7 @@ int Port::isNan(double r)
|
||||||
#else
|
#else
|
||||||
return __inline_isnan(r);
|
return __inline_isnan(r);
|
||||||
#endif
|
#endif
|
||||||
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__
|
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__
|
||||||
return isnan(r);
|
return isnan(r);
|
||||||
#else
|
#else
|
||||||
#undef isnan
|
#undef isnan
|
||||||
|
@ -822,7 +822,7 @@ int Port::isNan(longdouble r)
|
||||||
#else
|
#else
|
||||||
return __inline_isnan(r);
|
return __inline_isnan(r);
|
||||||
#endif
|
#endif
|
||||||
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__
|
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__
|
||||||
return isnan(r);
|
return isnan(r);
|
||||||
#else
|
#else
|
||||||
#undef isnan
|
#undef isnan
|
||||||
|
@ -850,7 +850,7 @@ int Port::isInfinity(double r)
|
||||||
{
|
{
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
return fpclassify(r) == FP_INFINITE;
|
return fpclassify(r) == FP_INFINITE;
|
||||||
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __DragonFly__
|
#elif __HAIKU__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__
|
||||||
return isinf(r);
|
return isinf(r);
|
||||||
#else
|
#else
|
||||||
#undef isinf
|
#undef isinf
|
||||||
|
@ -865,7 +865,7 @@ longdouble Port::sqrt(longdouble x)
|
||||||
|
|
||||||
longdouble Port::fmodl(longdouble x, longdouble y)
|
longdouble Port::fmodl(longdouble x, longdouble y)
|
||||||
{
|
{
|
||||||
#if __FreeBSD__ && __FreeBSD_version < 800000 || __OpenBSD__ || __DragonFly__
|
#if __FreeBSD__ && __FreeBSD_version < 800000 || __OpenBSD__ || __NetBSD__ || __DragonFly__
|
||||||
return ::fmod(x, y); // hack for now, fix later
|
return ::fmod(x, y); // hack for now, fix later
|
||||||
#else
|
#else
|
||||||
return ::fmodl(x, y);
|
return ::fmodl(x, y);
|
||||||
|
|
|
@ -37,10 +37,9 @@ static bool endsWith(const std::string &str, const std::string &end) {
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void CreateDirectoryOnDisk(llvm::StringRef fileName) {
|
static void CreateDirectoryOnDisk(llvm::StringRef fileName) {
|
||||||
llvm::StringRef dir(llvm::sys::path::parent_path(fileName));
|
auto dir = llvm::sys::path::parent_path(fileName);
|
||||||
if (!dir.empty() && !llvm::sys::fs::exists(dir)) {
|
if (!dir.empty() && !llvm::sys::fs::exists(dir)) {
|
||||||
std::error_code ec = llvm::sys::fs::create_directory(dir);
|
if (auto ec = llvm::sys::fs::create_directory(dir)) {
|
||||||
if (ec) {
|
|
||||||
error(Loc(), "failed to create path to file: %s\n%s", dir.data(),
|
error(Loc(), "failed to create path to file: %s\n%s", dir.data(),
|
||||||
ec.message().c_str());
|
ec.message().c_str());
|
||||||
fatal();
|
fatal();
|
||||||
|
@ -175,6 +174,9 @@ static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
|
||||||
args.push_back("-ldl");
|
args.push_back("-ldl");
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case llvm::Triple::FreeBSD:
|
case llvm::Triple::FreeBSD:
|
||||||
|
case llvm::Triple::NetBSD:
|
||||||
|
case llvm::Triple::OpenBSD:
|
||||||
|
case llvm::Triple::DragonFly:
|
||||||
addSoname = true;
|
addSoname = true;
|
||||||
args.push_back("-lpthread");
|
args.push_back("-lpthread");
|
||||||
args.push_back("-lm");
|
args.push_back("-lm");
|
||||||
|
@ -183,7 +185,8 @@ static int linkObjToBinaryGcc(bool sharedLib, bool fullyStatic) {
|
||||||
case llvm::Triple::Solaris:
|
case llvm::Triple::Solaris:
|
||||||
args.push_back("-lm");
|
args.push_back("-lm");
|
||||||
args.push_back("-lumem");
|
args.push_back("-lumem");
|
||||||
// solaris TODO
|
args.push_back("-lsocket");
|
||||||
|
args.push_back("-lnsl");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -125,9 +125,8 @@ static std::string getX86TargetCPU(const llvm::Triple &triple) {
|
||||||
// Intel Macs are relatively recent, take advantage of that.
|
// Intel Macs are relatively recent, take advantage of that.
|
||||||
if (triple.isOSDarwin()) {
|
if (triple.isOSDarwin()) {
|
||||||
return triple.isArch64Bit() ? "core2" : "yonah";
|
return triple.isArch64Bit() ? "core2" : "yonah";
|
||||||
|
|
||||||
// Everything else goes to x86-64 in 64-bit mode.
|
|
||||||
}
|
}
|
||||||
|
// Everything else goes to x86-64 in 64-bit mode.
|
||||||
if (triple.isArch64Bit()) {
|
if (triple.isArch64Bit()) {
|
||||||
return "x86-64";
|
return "x86-64";
|
||||||
}
|
}
|
||||||
|
@ -145,9 +144,15 @@ static std::string getX86TargetCPU(const llvm::Triple &triple) {
|
||||||
}
|
}
|
||||||
if (triple.getOSName().startswith("netbsd")) {
|
if (triple.getOSName().startswith("netbsd")) {
|
||||||
return "i486";
|
return "i486";
|
||||||
// All x86 devices running Android have core2 as their common
|
|
||||||
// denominator. This makes a better choice than pentium4.
|
|
||||||
}
|
}
|
||||||
|
if (triple.getOSName().startswith("openbsd")) {
|
||||||
|
return "i486";
|
||||||
|
}
|
||||||
|
if (triple.getOSName().startswith("dragonfly")) {
|
||||||
|
return "i486";
|
||||||
|
}
|
||||||
|
// All x86 devices running Android have core2 as their common
|
||||||
|
// denominator. This makes a better choice than pentium4.
|
||||||
if (triple.getEnvironment() == llvm::Triple::Android) {
|
if (triple.getEnvironment() == llvm::Triple::Android) {
|
||||||
return "core2";
|
return "core2";
|
||||||
|
|
||||||
|
@ -271,6 +276,11 @@ static FloatABI::Type getARMFloatABI(const llvm::Triple &triple,
|
||||||
return FloatABI::Soft;
|
return FloatABI::Soft;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (triple.getVendorName().startswith("hardfloat"))
|
||||||
|
return FloatABI::Hard;
|
||||||
|
if (triple.getVendorName().startswith("softfloat"))
|
||||||
|
return FloatABI::SoftFP;
|
||||||
|
|
||||||
switch (triple.getEnvironment()) {
|
switch (triple.getEnvironment()) {
|
||||||
case llvm::Triple::GNUEABIHF:
|
case llvm::Triple::GNUEABIHF:
|
||||||
return FloatABI::Hard;
|
return FloatABI::Hard;
|
||||||
|
@ -495,10 +505,27 @@ llvm::TargetMachine *createTargetMachine(
|
||||||
features.getString().c_str());
|
features.getString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (triple.isMacOSX() && relocModel == llvm::Reloc::Default) {
|
// Handle cases where LLVM picks wrong default relocModel
|
||||||
// OS X defaults to PIC (and as of 10.7.5/LLVM 3.1-3.3, TLS use leads
|
if (relocModel == llvm::Reloc::Default) {
|
||||||
// to crashes for non-PIC code). LLVM doesn't handle this.
|
if (triple.isOSDarwin()) {
|
||||||
relocModel = llvm::Reloc::PIC_;
|
// Darwin defaults to PIC (and as of 10.7.5/LLVM 3.1-3.3, TLS use leads
|
||||||
|
// to crashes for non-PIC code). LLVM doesn't handle this.
|
||||||
|
relocModel = llvm::Reloc::PIC_;
|
||||||
|
} else if (triple.getEnvironment() == llvm::Triple::Android) {
|
||||||
|
relocModel = llvm::Reloc::PIC_;
|
||||||
|
} else {
|
||||||
|
// ARM for other than Darwin or Android defaults to static
|
||||||
|
switch (triple.getArch()) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case llvm::Triple::arm:
|
||||||
|
case llvm::Triple::armeb:
|
||||||
|
case llvm::Triple::thumb:
|
||||||
|
case llvm::Triple::thumbeb:
|
||||||
|
relocModel = llvm::Reloc::Static;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (floatABI == FloatABI::Default) {
|
if (floatABI == FloatABI::Default) {
|
||||||
|
|
|
@ -346,27 +346,26 @@ void writeModule(llvm::Module *m, std::string filename) {
|
||||||
global.params.targetTriple->getOS() == llvm::Triple::AIX);
|
global.params.targetTriple->getOS() == llvm::Triple::AIX);
|
||||||
|
|
||||||
// eventually do our own path stuff, dmd's is a bit strange.
|
// eventually do our own path stuff, dmd's is a bit strange.
|
||||||
typedef llvm::SmallString<128> LLPath;
|
using LLPath = llvm::SmallString<128>;
|
||||||
|
|
||||||
|
#if LDC_LLVM_VER >= 306
|
||||||
|
using ErrorInfo = std::error_code;
|
||||||
|
#define ERRORINFO_STRING(errinfo) errinfo.message().c_str()
|
||||||
|
#else
|
||||||
|
using ErrorInfo = std::string;
|
||||||
|
#define ERRORINFO_STRING(errinfo) errinfo.c_str()
|
||||||
|
#endif
|
||||||
|
|
||||||
// write LLVM bitcode
|
// write LLVM bitcode
|
||||||
if (global.params.output_bc) {
|
if (global.params.output_bc) {
|
||||||
LLPath bcpath = LLPath(filename);
|
LLPath bcpath(filename);
|
||||||
llvm::sys::path::replace_extension(bcpath, global.bc_ext);
|
llvm::sys::path::replace_extension(bcpath, global.bc_ext);
|
||||||
Logger::println("Writing LLVM bitcode to: %s\n", bcpath.c_str());
|
Logger::println("Writing LLVM bitcode to: %s\n", bcpath.c_str());
|
||||||
#if LDC_LLVM_VER >= 306
|
ErrorInfo errinfo;
|
||||||
std::error_code errinfo;
|
|
||||||
#else
|
|
||||||
std::string errinfo;
|
|
||||||
#endif
|
|
||||||
llvm::raw_fd_ostream bos(bcpath.c_str(), errinfo, llvm::sys::fs::F_None);
|
llvm::raw_fd_ostream bos(bcpath.c_str(), errinfo, llvm::sys::fs::F_None);
|
||||||
if (bos.has_error()) {
|
if (bos.has_error()) {
|
||||||
error(Loc(), "cannot write LLVM bitcode file '%s': %s", bcpath.c_str(),
|
error(Loc(), "cannot write LLVM bitcode file '%s': %s", bcpath.c_str(),
|
||||||
#if LDC_LLVM_VER >= 306
|
ERRORINFO_STRING(errinfo));
|
||||||
errinfo
|
|
||||||
#else
|
|
||||||
errinfo.c_str()
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
llvm::WriteBitcodeToFile(m, bos);
|
llvm::WriteBitcodeToFile(m, bos);
|
||||||
|
@ -374,23 +373,14 @@ void writeModule(llvm::Module *m, std::string filename) {
|
||||||
|
|
||||||
// write LLVM IR
|
// write LLVM IR
|
||||||
if (global.params.output_ll) {
|
if (global.params.output_ll) {
|
||||||
LLPath llpath = LLPath(filename);
|
LLPath llpath(filename);
|
||||||
llvm::sys::path::replace_extension(llpath, global.ll_ext);
|
llvm::sys::path::replace_extension(llpath, global.ll_ext);
|
||||||
Logger::println("Writing LLVM asm to: %s\n", llpath.c_str());
|
Logger::println("Writing LLVM asm to: %s\n", llpath.c_str());
|
||||||
#if LDC_LLVM_VER >= 306
|
ErrorInfo errinfo;
|
||||||
std::error_code errinfo;
|
|
||||||
#else
|
|
||||||
std::string errinfo;
|
|
||||||
#endif
|
|
||||||
llvm::raw_fd_ostream aos(llpath.c_str(), errinfo, llvm::sys::fs::F_None);
|
llvm::raw_fd_ostream aos(llpath.c_str(), errinfo, llvm::sys::fs::F_None);
|
||||||
if (aos.has_error()) {
|
if (aos.has_error()) {
|
||||||
error(Loc(), "cannot write LLVM asm file '%s': %s", llpath.c_str(),
|
error(Loc(), "cannot write LLVM asm file '%s': %s", llpath.c_str(),
|
||||||
#if LDC_LLVM_VER >= 306
|
ERRORINFO_STRING(errinfo));
|
||||||
errinfo
|
|
||||||
#else
|
|
||||||
errinfo.c_str()
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
AssemblyAnnotator annotator;
|
AssemblyAnnotator annotator;
|
||||||
|
@ -399,18 +389,14 @@ void writeModule(llvm::Module *m, std::string filename) {
|
||||||
|
|
||||||
// write native assembly
|
// write native assembly
|
||||||
if (global.params.output_s || assembleExternally) {
|
if (global.params.output_s || assembleExternally) {
|
||||||
LLPath spath = LLPath(filename);
|
LLPath spath(filename);
|
||||||
llvm::sys::path::replace_extension(spath, global.s_ext);
|
llvm::sys::path::replace_extension(spath, global.s_ext);
|
||||||
if (!global.params.output_s) {
|
if (!global.params.output_s) {
|
||||||
llvm::sys::fs::createUniqueFile("ldc-%%%%%%%.s", spath);
|
llvm::sys::fs::createUniqueFile("ldc-%%%%%%%.s", spath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::println("Writing native asm to: %s\n", spath.c_str());
|
Logger::println("Writing native asm to: %s\n", spath.c_str());
|
||||||
#if LDC_LLVM_VER >= 306
|
ErrorInfo errinfo;
|
||||||
std::error_code errinfo;
|
|
||||||
#else
|
|
||||||
std::string errinfo;
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
llvm::raw_fd_ostream out(spath.c_str(), errinfo, llvm::sys::fs::F_None);
|
llvm::raw_fd_ostream out(spath.c_str(), errinfo, llvm::sys::fs::F_None);
|
||||||
#if LDC_LLVM_VER >= 306
|
#if LDC_LLVM_VER >= 306
|
||||||
|
@ -422,20 +408,13 @@ void writeModule(llvm::Module *m, std::string filename) {
|
||||||
codegenModule(*gTargetMachine, *m, out,
|
codegenModule(*gTargetMachine, *m, out,
|
||||||
llvm::TargetMachine::CGFT_AssemblyFile);
|
llvm::TargetMachine::CGFT_AssemblyFile);
|
||||||
} else {
|
} else {
|
||||||
error(Loc(), "cannot write native asm: %s",
|
error(Loc(), "cannot write native asm: %s", ERRORINFO_STRING(errinfo));
|
||||||
#if LDC_LLVM_VER >= 306
|
|
||||||
errinfo
|
|
||||||
#else
|
|
||||||
errinfo.c_str()
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assembleExternally) {
|
if (assembleExternally) {
|
||||||
LLPath objpath(filename);
|
assemble(spath.str(), filename);
|
||||||
assemble(spath.str(), objpath.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.params.output_s) {
|
if (!global.params.output_s) {
|
||||||
|
@ -444,15 +423,11 @@ void writeModule(llvm::Module *m, std::string filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.params.output_o && !assembleExternally) {
|
if (global.params.output_o && !assembleExternally) {
|
||||||
LLPath objpath = LLPath(filename);
|
Logger::println("Writing object file to: %s\n", filename.c_str());
|
||||||
Logger::println("Writing object file to: %s\n", objpath.c_str());
|
ErrorInfo errinfo;
|
||||||
#if LDC_LLVM_VER >= 306
|
|
||||||
std::error_code errinfo;
|
|
||||||
#else
|
|
||||||
std::string errinfo;
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
llvm::raw_fd_ostream out(objpath.c_str(), errinfo, llvm::sys::fs::F_None);
|
llvm::raw_fd_ostream out(filename.c_str(), errinfo,
|
||||||
|
llvm::sys::fs::F_None);
|
||||||
#if LDC_LLVM_VER >= 306
|
#if LDC_LLVM_VER >= 306
|
||||||
if (!errinfo)
|
if (!errinfo)
|
||||||
#else
|
#else
|
||||||
|
@ -462,15 +437,11 @@ void writeModule(llvm::Module *m, std::string filename) {
|
||||||
codegenModule(*gTargetMachine, *m, out,
|
codegenModule(*gTargetMachine, *m, out,
|
||||||
llvm::TargetMachine::CGFT_ObjectFile);
|
llvm::TargetMachine::CGFT_ObjectFile);
|
||||||
} else {
|
} else {
|
||||||
error(Loc(), "cannot write object file: %s",
|
error(Loc(), "cannot write object file: %s", ERRORINFO_STRING(errinfo));
|
||||||
#if LDC_LLVM_VER >= 306
|
|
||||||
errinfo
|
|
||||||
#else
|
|
||||||
errinfo.c_str()
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef ERRORINFO_STRING
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ struct AArch64TargetABI : TargetABI {
|
||||||
// and set 'ap' to its address.
|
// and set 'ap' to its address.
|
||||||
LLValue *valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem");
|
LLValue *valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem");
|
||||||
valistmem = DtoBitCast(valistmem, getVoidPtrType());
|
valistmem = DtoBitCast(valistmem, getVoidPtrType());
|
||||||
DtoStore(valistmem, pAp); // ap = (void*)__va_list_mem
|
DtoStore(valistmem, DtoBitCast(pAp, getPtrToType(getVoidPtrType())));
|
||||||
|
|
||||||
// pass a void* pointer to the actual struct to LLVM's va_start intrinsic
|
// pass a void* pointer to the actual struct to LLVM's va_start intrinsic
|
||||||
return valistmem;
|
return valistmem;
|
||||||
|
|
124
gen/abi-arm.cpp
Normal file
124
gen/abi-arm.cpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
//===-- abi-arm.cpp ---------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// LDC – the LLVM D compiler
|
||||||
|
//
|
||||||
|
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||||||
|
// file for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
/*
|
||||||
|
ARM ABI based on AAPCS (Procedure Call Standard for the ARM Architecture)
|
||||||
|
|
||||||
|
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gen/abi.h"
|
||||||
|
#include "gen/abi-generic.h"
|
||||||
|
#include "gen/abi-arm.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct CompositeToArray32 : ABIRewrite {
|
||||||
|
LLValue *get(Type *dty, LLValue *v) override {
|
||||||
|
Logger::println("rewriting i32 array -> as %s", dty->toChars());
|
||||||
|
LLValue *lval = DtoRawAlloca(v->getType(), 0);
|
||||||
|
DtoStore(v, lval);
|
||||||
|
|
||||||
|
LLType *pTy = getPtrToType(DtoType(dty));
|
||||||
|
return DtoLoad(DtoBitCast(lval, pTy), "get-result");
|
||||||
|
}
|
||||||
|
|
||||||
|
LLValue *put(DValue *dv) override {
|
||||||
|
Type *dty = dv->getType();
|
||||||
|
Logger::println("rewriting %s -> as i32 array", dty->toChars());
|
||||||
|
LLType *t = type(dty, nullptr);
|
||||||
|
return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t)));
|
||||||
|
}
|
||||||
|
|
||||||
|
LLType *type(Type *t, LLType *) override {
|
||||||
|
// An i32 array that will hold Type 't'
|
||||||
|
size_t sz = (t->size() + 3) / 4;
|
||||||
|
return LLArrayType::get(LLIntegerType::get(gIR->context(), 32), sz);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ArmTargetABI : TargetABI {
|
||||||
|
HFAToArray hfaToArray;
|
||||||
|
CompositeToArray32 compositeToArray32;
|
||||||
|
IntegerRewrite integerRewrite;
|
||||||
|
|
||||||
|
bool returnInArg(TypeFunction *tf) override {
|
||||||
|
// AAPCS 5.4 wants composites > 4-bytes returned by arg except for
|
||||||
|
// Homogeneous Aggregates of up-to 4 float types (6.1.2.1) - an HFA.
|
||||||
|
// TODO: see if Tsarray should be candidate for HFA.
|
||||||
|
if (tf->isref)
|
||||||
|
return false;
|
||||||
|
Type *rt = tf->next->toBasetype();
|
||||||
|
|
||||||
|
// For extern(D), always return structs by arg because of problem with
|
||||||
|
// non-POD structs (failure in std.algorithm.move when struct has a ctor).
|
||||||
|
// TODO: figure out what the problem is
|
||||||
|
if (tf->linkage == LINKd)
|
||||||
|
return rt->ty == Tsarray || rt->ty == Tstruct;
|
||||||
|
|
||||||
|
return rt->ty == Tsarray ||
|
||||||
|
(rt->ty == Tstruct && rt->size() > 4 && !isHFA((TypeStruct *)rt));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool passByVal(Type *t) override {
|
||||||
|
// AAPCS does not pass byval
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Note: the codegen is horrible for Tsarrays passed this way - tries to do
|
||||||
|
// copy without a loop for huge arrays. Would be better if byval was used
|
||||||
|
// for arrays, but then there is an optimizer problem in the "top-down list
|
||||||
|
// latency scheduler" pass that reorders instructions incorrectly if byval
|
||||||
|
// used.
|
||||||
|
}
|
||||||
|
|
||||||
|
void rewriteFunctionType(TypeFunction *tf, IrFuncTy &fty) override {
|
||||||
|
Type *retTy = fty.ret->type->toBasetype();
|
||||||
|
if (!fty.ret->byref && retTy->ty == Tstruct) {
|
||||||
|
// Rewrite HFAs only because union HFAs are turned into IR types that are
|
||||||
|
// non-HFA and messes up register selection
|
||||||
|
if (isHFA((TypeStruct *)retTy, &fty.ret->ltype)) {
|
||||||
|
fty.ret->rewrite = &hfaToArray;
|
||||||
|
} else {
|
||||||
|
fty.ret->rewrite = &integerRewrite;
|
||||||
|
fty.ret->ltype = integerRewrite.type(fty.ret->type, fty.ret->ltype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto arg : fty.args) {
|
||||||
|
if (!arg->byref)
|
||||||
|
rewriteArgument(fty, *arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override {
|
||||||
|
// structs and arrays need rewrite as i32 arrays. This keeps data layout
|
||||||
|
// unchanged when passed in registers r0-r3 and is necessary to match C ABI
|
||||||
|
// for struct passing. Without out this rewrite, each field or array
|
||||||
|
// element is passed in own register. For example: char[4] now all fits in
|
||||||
|
// r0, where before it consumed r0-r3.
|
||||||
|
Type *ty = arg.type->toBasetype();
|
||||||
|
|
||||||
|
// TODO: want to also rewrite Tsarray as i32 arrays, but sometimes
|
||||||
|
// llvm selects an aligned ldrd instruction even though the ptr is
|
||||||
|
// unaligned (e.g. walking through members of array char[5][]).
|
||||||
|
// if (ty->ty == Tstruct || ty->ty == Tsarray)
|
||||||
|
if (ty->ty == Tstruct) {
|
||||||
|
// Rewrite HFAs only because union HFAs are turned into IR types that are
|
||||||
|
// non-HFA and messes up register selection
|
||||||
|
if (isHFA((TypeStruct *)ty, &arg.ltype)) {
|
||||||
|
arg.rewrite = &hfaToArray;
|
||||||
|
} else {
|
||||||
|
arg.rewrite = &compositeToArray32;
|
||||||
|
arg.ltype = compositeToArray32.type(arg.type, arg.ltype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TargetABI *getArmTargetABI() { return new ArmTargetABI; }
|
21
gen/abi-arm.h
Normal file
21
gen/abi-arm.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//===-- gen/abi-arm.h - ARM ABI description -------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// LDC – the LLVM D compiler
|
||||||
|
//
|
||||||
|
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||||||
|
// file for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// The ABI implementation used for ARM targets.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LDC_GEN_ABI_ARM_H
|
||||||
|
#define LDC_GEN_ABI_ARM_H
|
||||||
|
|
||||||
|
struct TargetABI;
|
||||||
|
|
||||||
|
TargetABI *getArmTargetABI();
|
||||||
|
|
||||||
|
#endif
|
|
@ -227,4 +227,34 @@ struct ExplicitByvalRewrite : ABIRewrite {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewrite Homogeneous Homogeneous Floating-point Aggregate (HFA) as array of
|
||||||
|
* float type.
|
||||||
|
*/
|
||||||
|
struct HFAToArray : ABIRewrite {
|
||||||
|
LLValue *get(Type *dty, LLValue *v) override {
|
||||||
|
Logger::println("rewriting array -> as HFA %s", dty->toChars());
|
||||||
|
LLValue *lval = DtoRawAlloca(v->getType(), 0);
|
||||||
|
DtoStore(v, lval);
|
||||||
|
|
||||||
|
LLType *pTy = getPtrToType(DtoType(dty));
|
||||||
|
return DtoLoad(DtoBitCast(lval, pTy), "get-result");
|
||||||
|
}
|
||||||
|
|
||||||
|
LLValue *put(DValue *dv) override {
|
||||||
|
Type *dty = dv->getType();
|
||||||
|
Logger::println("rewriting HFA %s -> as array", dty->toChars());
|
||||||
|
LLType *t = type(dty, nullptr);
|
||||||
|
return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t)));
|
||||||
|
}
|
||||||
|
|
||||||
|
LLType *type(Type *dty, LLType *) override {
|
||||||
|
assert(dty->ty == Tstruct);
|
||||||
|
LLType *floatArrayType = nullptr;
|
||||||
|
if (TargetABI::isHFA((TypeStruct *)dty, &floatArrayType))
|
||||||
|
return floatArrayType;
|
||||||
|
llvm_unreachable("Type dty should be an HFA");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
113
gen/abi.cpp
113
gen/abi.cpp
|
@ -12,6 +12,7 @@
|
||||||
#include "id.h"
|
#include "id.h"
|
||||||
#include "gen/abi-generic.h"
|
#include "gen/abi-generic.h"
|
||||||
#include "gen/abi-aarch64.h"
|
#include "gen/abi-aarch64.h"
|
||||||
|
#include "gen/abi-arm.h"
|
||||||
#include "gen/abi-mips64.h"
|
#include "gen/abi-mips64.h"
|
||||||
#include "gen/abi-ppc64.h"
|
#include "gen/abi-ppc64.h"
|
||||||
#include "gen/abi-win64.h"
|
#include "gen/abi-win64.h"
|
||||||
|
@ -97,6 +98,113 @@ LLValue *ABIRewrite::loadFromMemory(LLValue *address, LLType *asType,
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// A Homogeneous Floating-point Aggregate (HFA) is an ARM/AArch64 concept that
|
||||||
|
// consists of up to 4 of same floating point type. D floats of same size are
|
||||||
|
// considered as same (e.g. ifloat and float are same). It is the aggregate
|
||||||
|
// final data layout that matters so nested structs, unions, and sarrays can
|
||||||
|
// result in an HFA.
|
||||||
|
//
|
||||||
|
// simple HFAs: struct F1 {float f;} struct D4 {double a,b,c,d;}
|
||||||
|
// interesting HFA: struct {F1[2] vals; float weight;}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool isNestedHFA(const TypeStruct *t, d_uns64 &floatSize, int &num,
|
||||||
|
uinteger_t adim) {
|
||||||
|
// Used internally by isHFA() to check struct recursively for HFA-ness.
|
||||||
|
// Return true if struct 't' is part of an HFA where 'floatSize' is sizeof
|
||||||
|
// the float and 'num' is number of these floats so far. On return, 'num'
|
||||||
|
// is updated to the total number of floats in the HFA. Set 'floatSize'
|
||||||
|
// to 0 discover the sizeof the float. When struct 't' is part of an
|
||||||
|
// sarray, 'adim' is the dimension of that array, otherwise it is 1.
|
||||||
|
VarDeclarations fields = t->sym->fields;
|
||||||
|
|
||||||
|
// HFA can't contains an empty struct
|
||||||
|
if (fields.dim == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Accumulate number of floats in HFA
|
||||||
|
int n;
|
||||||
|
|
||||||
|
// For unions, need to find field with most floats
|
||||||
|
int maxn = num;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fields.dim; ++i) {
|
||||||
|
Type *field = fields[i]->type;
|
||||||
|
|
||||||
|
// reset to initial num floats (all union fields are at offset 0)
|
||||||
|
if (fields[i]->offset == 0)
|
||||||
|
n = num;
|
||||||
|
|
||||||
|
// reset dim to dimension of sarray we are in (will be 1 if not)
|
||||||
|
uinteger_t dim = adim;
|
||||||
|
|
||||||
|
// Field is an array. Process the arrayof type and multiply dim by
|
||||||
|
// array dim. Note that empty arrays immediately exclude this struct
|
||||||
|
// from HFA status.
|
||||||
|
if (field->ty == Tsarray) {
|
||||||
|
TypeSArray *array = (TypeSArray *)field;
|
||||||
|
if (array->dim->toUInteger() == 0)
|
||||||
|
return false;
|
||||||
|
field = array->nextOf();
|
||||||
|
dim *= array->dim->toUInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field->ty == Tstruct) {
|
||||||
|
if (!isNestedHFA((TypeStruct *)field, floatSize, n, dim))
|
||||||
|
return false;
|
||||||
|
} else if (field->isfloating()) {
|
||||||
|
d_uns64 sz = field->size();
|
||||||
|
n += dim;
|
||||||
|
|
||||||
|
if (field->iscomplex()) {
|
||||||
|
sz /= 2; // complex is 2 floats, adjust sz
|
||||||
|
n += dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (floatSize == 0) // discovered floatSize
|
||||||
|
floatSize = sz;
|
||||||
|
else if (sz != floatSize) // different float size, reject
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (n > 4)
|
||||||
|
return false; // too many floats for HFA, reject
|
||||||
|
} else {
|
||||||
|
return false; // reject all other types
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > maxn)
|
||||||
|
maxn = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
num = maxn;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TargetABI::isHFA(TypeStruct *t, llvm::Type **rewriteType) {
|
||||||
|
d_uns64 floatSize = 0;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
if (isNestedHFA(t, floatSize, num, 1)) {
|
||||||
|
if (rewriteType) {
|
||||||
|
llvm::Type *floatType = nullptr;
|
||||||
|
switch (floatSize) {
|
||||||
|
case 4:
|
||||||
|
floatType = llvm::Type::getFloatTy(gIR->context());
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
floatType = llvm::Type::getDoubleTy(gIR->context());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Unexpected size for float type");
|
||||||
|
}
|
||||||
|
*rewriteType = LLArrayType::get(floatType, num);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool TargetABI::isAggregate(Type *t) {
|
bool TargetABI::isAggregate(Type *t) {
|
||||||
TY ty = t->toBasetype()->ty;
|
TY ty = t->toBasetype()->ty;
|
||||||
// FIXME: dynamic arrays can currently not be rewritten as they are used
|
// FIXME: dynamic arrays can currently not be rewritten as they are used
|
||||||
|
@ -235,6 +343,11 @@ TargetABI *TargetABI::getTarget() {
|
||||||
case llvm::Triple::aarch64:
|
case llvm::Triple::aarch64:
|
||||||
case llvm::Triple::aarch64_be:
|
case llvm::Triple::aarch64_be:
|
||||||
return getAArch64TargetABI();
|
return getAArch64TargetABI();
|
||||||
|
case llvm::Triple::arm:
|
||||||
|
case llvm::Triple::armeb:
|
||||||
|
case llvm::Triple::thumb:
|
||||||
|
case llvm::Triple::thumbeb:
|
||||||
|
return getArmTargetABI();
|
||||||
default:
|
default:
|
||||||
Logger::cout() << "WARNING: Unknown ABI, guessing...\n";
|
Logger::cout() << "WARNING: Unknown ABI, guessing...\n";
|
||||||
return new UnknownTargetABI;
|
return new UnknownTargetABI;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
class Type;
|
class Type;
|
||||||
class TypeFunction;
|
class TypeFunction;
|
||||||
|
class TypeStruct;
|
||||||
struct IrFuncTy;
|
struct IrFuncTy;
|
||||||
struct IrFuncTyArg;
|
struct IrFuncTyArg;
|
||||||
class DValue;
|
class DValue;
|
||||||
|
@ -148,9 +149,15 @@ struct TargetABI {
|
||||||
/// Must match the alias in druntime.
|
/// Must match the alias in druntime.
|
||||||
virtual Type *vaListType();
|
virtual Type *vaListType();
|
||||||
|
|
||||||
protected:
|
|
||||||
/***** Static Helpers *****/
|
/***** Static Helpers *****/
|
||||||
|
|
||||||
|
/// Check if struct 't' is a Homogeneous Floating-point Aggregate (HFA)
|
||||||
|
/// consisting of up to 4 of same floating point type. If so, optionally
|
||||||
|
/// produce the rewriteType: an array of that floating point type
|
||||||
|
static bool isHFA(TypeStruct *t, llvm::Type **rewriteType = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
/// Returns true if the D type is an aggregate:
|
/// Returns true if the D type is an aggregate:
|
||||||
/// * struct
|
/// * struct
|
||||||
/// * static/dynamic array
|
/// * static/dynamic array
|
||||||
|
|
|
@ -151,9 +151,9 @@ ldc::DIType ldc::DIBuilder::CreateBasicType(Type *type) {
|
||||||
"Unsupported basic type for debug info in DIBuilder::CreateBasicType");
|
"Unsupported basic type for debug info in DIBuilder::CreateBasicType");
|
||||||
}
|
}
|
||||||
|
|
||||||
return DBuilder.createBasicType(type->toChars(), // name
|
return DBuilder.createBasicType(type->toChars(), // name
|
||||||
getTypeBitSize(T), // size (bits)
|
getTypeAllocSize(T) * 8, // size (bits)
|
||||||
getABITypeAlign(T) * 8, // align (bits)
|
getABITypeAlign(T) * 8, // align (bits)
|
||||||
Encoding);
|
Encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ ldc::DIType ldc::DIBuilder::CreateEnumType(Type *type) {
|
||||||
|
|
||||||
return DBuilder.createEnumerationType(
|
return DBuilder.createEnumerationType(
|
||||||
GetCU(), Name, File, LineNumber,
|
GetCU(), Name, File, LineNumber,
|
||||||
getTypeBitSize(T), // size (bits)
|
getTypeAllocSize(T) * 8, // size (bits)
|
||||||
getABITypeAlign(T) * 8, // align (bits)
|
getABITypeAlign(T) * 8, // align (bits)
|
||||||
DBuilder.getOrCreateArray(subscripts), // subscripts
|
DBuilder.getOrCreateArray(subscripts), // subscripts
|
||||||
CreateTypeDescription(te->sym->memtype, false));
|
CreateTypeDescription(te->sym->memtype, false));
|
||||||
|
@ -201,9 +201,9 @@ ldc::DIType ldc::DIBuilder::CreatePointerType(Type *type) {
|
||||||
ldc::DIType basetype(CreateTypeDescription(nt, false));
|
ldc::DIType basetype(CreateTypeDescription(nt, false));
|
||||||
|
|
||||||
return DBuilder.createPointerType(basetype,
|
return DBuilder.createPointerType(basetype,
|
||||||
getTypeBitSize(T), // size (bits)
|
getTypeAllocSize(T) * 8, // size (bits)
|
||||||
getABITypeAlign(T) * 8, // align (bits)
|
getABITypeAlign(T) * 8, // align (bits)
|
||||||
type->toChars() // name
|
type->toChars() // name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ ldc::DIType ldc::DIBuilder::CreateVectorType(Type *type) {
|
||||||
ldc::DIType basetype(CreateTypeDescription(te, false));
|
ldc::DIType basetype(CreateTypeDescription(te, false));
|
||||||
|
|
||||||
return DBuilder.createVectorType(
|
return DBuilder.createVectorType(
|
||||||
getTypeBitSize(T), // size (bits)
|
getTypeAllocSize(T) * 8, // size (bits)
|
||||||
getABITypeAlign(T) * 8, // align (bits)
|
getABITypeAlign(T) * 8, // align (bits)
|
||||||
basetype, // element type
|
basetype, // element type
|
||||||
DBuilder.getOrCreateArray(subscripts) // subscripts
|
DBuilder.getOrCreateArray(subscripts) // subscripts
|
||||||
|
@ -260,14 +260,14 @@ ldc::DIType ldc::DIBuilder::CreateMemberType(unsigned linnum, Type *type,
|
||||||
}
|
}
|
||||||
|
|
||||||
return DBuilder.createMemberType(GetCU(),
|
return DBuilder.createMemberType(GetCU(),
|
||||||
c_name, // name
|
c_name, // name
|
||||||
file, // file
|
file, // file
|
||||||
linnum, // line number
|
linnum, // line number
|
||||||
getTypeBitSize(T), // size (bits)
|
getTypeAllocSize(T) * 8, // size (bits)
|
||||||
getABITypeAlign(T) * 8, // align (bits)
|
getABITypeAlign(T) * 8, // align (bits)
|
||||||
offset * 8, // offset (bits)
|
offset * 8, // offset (bits)
|
||||||
Flags, // flags
|
Flags, // flags
|
||||||
basetype // derived from
|
basetype // derived from
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,18 +381,18 @@ ldc::DIType ldc::DIBuilder::CreateCompositeType(Type *type) {
|
||||||
name, // name
|
name, // name
|
||||||
file, // file where defined
|
file, // file where defined
|
||||||
linnum, // line number where defined
|
linnum, // line number where defined
|
||||||
getTypeBitSize(T), // size in bits
|
getTypeAllocSize(T) * 8, // size in bits
|
||||||
getABITypeAlign(T) * 8, // alignment in bits
|
getABITypeAlign(T) * 8, // alignment in bits
|
||||||
0, // offset in bits,
|
0, // offset in bits,
|
||||||
DIFlags::FlagFwdDecl, // flags
|
DIFlags::FlagFwdDecl, // flags
|
||||||
derivedFrom, // DerivedFrom
|
derivedFrom, // DerivedFrom
|
||||||
elemsArray);
|
elemsArray);
|
||||||
} else {
|
} else {
|
||||||
ret = DBuilder.createStructType(CU, // compile unit where defined
|
ret = DBuilder.createStructType(CU, // compile unit where defined
|
||||||
name, // name
|
name, // name
|
||||||
file, // file where defined
|
file, // file where defined
|
||||||
linnum, // line number where defined
|
linnum, // line number where defined
|
||||||
getTypeBitSize(T), // size in bits
|
getTypeAllocSize(T) * 8, // size in bits
|
||||||
getABITypeAlign(T) * 8, // alignment in bits
|
getABITypeAlign(T) * 8, // alignment in bits
|
||||||
DIFlags::FlagFwdDecl, // flags
|
DIFlags::FlagFwdDecl, // flags
|
||||||
derivedFrom, // DerivedFrom
|
derivedFrom, // DerivedFrom
|
||||||
|
@ -434,9 +434,9 @@ ldc::DIType ldc::DIBuilder::CreateArrayType(Type *type) {
|
||||||
llvm::StringRef(), // Name TODO: Really no name for arrays? t->toChars()?
|
llvm::StringRef(), // Name TODO: Really no name for arrays? t->toChars()?
|
||||||
file, // File
|
file, // File
|
||||||
0, // LineNo
|
0, // LineNo
|
||||||
getTypeBitSize(T), // size in bits
|
getTypeAllocSize(T) * 8, // size in bits
|
||||||
getABITypeAlign(T) * 8, // alignment in bits
|
getABITypeAlign(T) * 8, // alignment in bits
|
||||||
0, // What here?
|
0, // What here?
|
||||||
#if LDC_LLVM_VER >= 307
|
#if LDC_LLVM_VER >= 307
|
||||||
nullptr, // DerivedFrom
|
nullptr, // DerivedFrom
|
||||||
#else
|
#else
|
||||||
|
@ -469,7 +469,7 @@ ldc::DIType ldc::DIBuilder::CreateSArrayType(Type *type) {
|
||||||
ldc::DIType basetype(CreateTypeDescription(t, false));
|
ldc::DIType basetype(CreateTypeDescription(t, false));
|
||||||
|
|
||||||
return DBuilder.createArrayType(
|
return DBuilder.createArrayType(
|
||||||
getTypeBitSize(T), // size (bits)
|
getTypeAllocSize(T) * 8, // size (bits)
|
||||||
getABITypeAlign(T) * 8, // align (bits)
|
getABITypeAlign(T) * 8, // align (bits)
|
||||||
basetype, // element type
|
basetype, // element type
|
||||||
DBuilder.getOrCreateArray(subscripts) // subscripts
|
DBuilder.getOrCreateArray(subscripts) // subscripts
|
||||||
|
|
|
@ -75,8 +75,7 @@ bool isTargetWindowsMSVC() {
|
||||||
|
|
||||||
LLValue *DtoNew(Loc &loc, Type *newtype) {
|
LLValue *DtoNew(Loc &loc, Type *newtype) {
|
||||||
// get runtime function
|
// get runtime function
|
||||||
llvm::Function *fn =
|
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_allocmemoryT");
|
||||||
getRuntimeFunction(loc, gIR->module, "_d_allocmemoryT");
|
|
||||||
// get type info
|
// get type info
|
||||||
LLConstant *ti = DtoTypeInfoOf(newtype);
|
LLConstant *ti = DtoTypeInfoOf(newtype);
|
||||||
assert(isaPointer(ti));
|
assert(isaPointer(ti));
|
||||||
|
@ -96,16 +95,14 @@ LLValue *DtoNewStruct(Loc &loc, TypeStruct *newtype) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoDeleteMemory(Loc &loc, DValue *ptr) {
|
void DtoDeleteMemory(Loc &loc, DValue *ptr) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delmemory");
|
||||||
getRuntimeFunction(loc, gIR->module, "_d_delmemory");
|
|
||||||
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoDeleteStruct(Loc &loc, DValue *ptr) {
|
void DtoDeleteStruct(Loc &loc, DValue *ptr) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delstruct");
|
||||||
getRuntimeFunction(loc, gIR->module, "_d_delstruct");
|
|
||||||
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)),
|
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)),
|
||||||
|
@ -114,24 +111,21 @@ void DtoDeleteStruct(Loc &loc, DValue *ptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoDeleteClass(Loc &loc, DValue *inst) {
|
void DtoDeleteClass(Loc &loc, DValue *inst) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delclass");
|
||||||
getRuntimeFunction(loc, gIR->module, "_d_delclass");
|
|
||||||
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoDeleteInterface(Loc &loc, DValue *inst) {
|
void DtoDeleteInterface(Loc &loc, DValue *inst) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delinterface");
|
||||||
getRuntimeFunction(loc, gIR->module, "_d_delinterface");
|
|
||||||
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoDeleteArray(Loc &loc, DValue *arr) {
|
void DtoDeleteArray(Loc &loc, DValue *arr) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delarray_t");
|
||||||
getRuntimeFunction(loc, gIR->module, "_d_delarray_t");
|
|
||||||
llvm::FunctionType *fty = fn->getFunctionType();
|
llvm::FunctionType *fty = fn->getFunctionType();
|
||||||
|
|
||||||
// the TypeInfo argument must be null if the type has no dtor
|
// the TypeInfo argument must be null if the type has no dtor
|
||||||
|
@ -195,8 +189,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) {
|
||||||
// get runtime function
|
// get runtime function
|
||||||
llvm::Function *fn =
|
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_allocmemory");
|
||||||
getRuntimeFunction(loc, gIR->module, "_d_allocmemory");
|
|
||||||
// parameters
|
// parameters
|
||||||
LLValue *size = DtoConstSize_t(getTypeAllocSize(lltype));
|
LLValue *size = DtoConstSize_t(getTypeAllocSize(lltype));
|
||||||
// call runtime allocator
|
// call runtime allocator
|
||||||
|
@ -600,6 +593,23 @@ DValue *DtoCastVector(Loc &loc, DValue *val, Type *to) {
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DValue *DtoCastStruct(Loc &loc, DValue *val, Type *to) {
|
||||||
|
Type *const totype = to->toBasetype();
|
||||||
|
if (totype->ty == Tstruct) {
|
||||||
|
// This a cast to repaint a struct to another type, which the language
|
||||||
|
// allows for identical layouts (opCast() and so on have been lowered
|
||||||
|
// earlier by the frontend).
|
||||||
|
llvm::Value *rv = val->getRVal();
|
||||||
|
llvm::Value *result =
|
||||||
|
DtoBitCast(rv, DtoType(to)->getPointerTo(), rv->getName() + ".repaint");
|
||||||
|
return new DImValue(to, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
error(loc, "Internal Compiler Error: Invalid struct cast from '%s' to '%s'",
|
||||||
|
val->getType()->toChars(), to->toChars());
|
||||||
|
fatal();
|
||||||
|
}
|
||||||
|
|
||||||
DValue *DtoCast(Loc &loc, DValue *val, Type *to) {
|
DValue *DtoCast(Loc &loc, DValue *val, Type *to) {
|
||||||
Type *fromtype = val->getType()->toBasetype();
|
Type *fromtype = val->getType()->toBasetype();
|
||||||
Type *totype = to->toBasetype();
|
Type *totype = to->toBasetype();
|
||||||
|
@ -629,6 +639,7 @@ DValue *DtoCast(Loc &loc, DValue *val, Type *to) {
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
if (fromtype->ty == Tvector) {
|
if (fromtype->ty == Tvector) {
|
||||||
|
// First, handle vector types (which can also be isintegral()).
|
||||||
return DtoCastVector(loc, val, to);
|
return DtoCastVector(loc, val, to);
|
||||||
}
|
}
|
||||||
if (fromtype->isintegral()) {
|
if (fromtype->isintegral()) {
|
||||||
|
@ -640,27 +651,33 @@ DValue *DtoCast(Loc &loc, DValue *val, Type *to) {
|
||||||
if (fromtype->isfloating()) {
|
if (fromtype->isfloating()) {
|
||||||
return DtoCastFloat(loc, val, to);
|
return DtoCastFloat(loc, val, to);
|
||||||
}
|
}
|
||||||
if (fromtype->ty == Tclass) {
|
|
||||||
|
switch (fromtype->ty) {
|
||||||
|
case Tclass:
|
||||||
return DtoCastClass(loc, val, to);
|
return DtoCastClass(loc, val, to);
|
||||||
}
|
case Tarray:
|
||||||
if (fromtype->ty == Tarray || fromtype->ty == Tsarray) {
|
case Tsarray:
|
||||||
return DtoCastArray(loc, val, to);
|
return DtoCastArray(loc, val, to);
|
||||||
}
|
case Tpointer:
|
||||||
if (fromtype->ty == Tpointer || fromtype->ty == Tfunction) {
|
case Tfunction:
|
||||||
return DtoCastPtr(loc, val, to);
|
return DtoCastPtr(loc, val, to);
|
||||||
}
|
case Tdelegate:
|
||||||
if (fromtype->ty == Tdelegate) {
|
|
||||||
return DtoCastDelegate(loc, val, to);
|
return DtoCastDelegate(loc, val, to);
|
||||||
}
|
case Tstruct:
|
||||||
if (fromtype->ty == Tnull) {
|
return DtoCastStruct(loc, val, to);
|
||||||
|
case Tnull:
|
||||||
return DtoNullValue(to, loc);
|
return DtoNullValue(to, loc);
|
||||||
|
case Taarray:
|
||||||
|
if (totype->ty == Taarray) {
|
||||||
|
// Do nothing, the types will match up anyway.
|
||||||
|
return new DImValue(to, val->getRVal());
|
||||||
|
}
|
||||||
|
// fall-through
|
||||||
|
default:
|
||||||
|
error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(),
|
||||||
|
to->toChars());
|
||||||
|
fatal();
|
||||||
}
|
}
|
||||||
if (fromtype->ty == totype->ty) {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(),
|
|
||||||
to->toChars());
|
|
||||||
fatal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1397,7 +1414,6 @@ LLValue *makeLValue(Loc &loc, DValue *value) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void callPostblit(Loc &loc, Expression *exp, LLValue *val) {
|
void callPostblit(Loc &loc, Expression *exp, LLValue *val) {
|
||||||
|
|
||||||
Type *tb = exp->type->toBasetype();
|
Type *tb = exp->type->toBasetype();
|
||||||
if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar ||
|
if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar ||
|
||||||
exp->op == TOKthis || exp->op == TOKindex) &&
|
exp->op == TOKthis || exp->op == TOKindex) &&
|
||||||
|
|
|
@ -178,8 +178,7 @@ void DtoDefineNakedFunction(FuncDeclaration *fd) {
|
||||||
// Windows is different
|
// Windows is different
|
||||||
else if (isWin) {
|
else if (isWin) {
|
||||||
std::string fullMangle;
|
std::string fullMangle;
|
||||||
if (global.params.targetTriple->isWindowsGNUEnvironment() &&
|
if (!global.params.targetTriple->isArch64Bit()) {
|
||||||
!global.params.targetTriple->isArch64Bit()) {
|
|
||||||
fullMangle = "_";
|
fullMangle = "_";
|
||||||
}
|
}
|
||||||
fullMangle += mangle;
|
fullMangle += mangle;
|
||||||
|
|
|
@ -42,8 +42,14 @@ RTTIBuilder::RTTIBuilder(AggregateDeclaration *base_class) {
|
||||||
void RTTIBuilder::push(llvm::Constant *C) {
|
void RTTIBuilder::push(llvm::Constant *C) {
|
||||||
// We need to explicitly zero any padding bytes as per TDPL §7.1.1 (and
|
// We need to explicitly zero any padding bytes as per TDPL §7.1.1 (and
|
||||||
// also match the struct type lowering code here).
|
// also match the struct type lowering code here).
|
||||||
const uint64_t fieldStart = llvm::RoundUpToAlignment(
|
const uint64_t fieldStart =
|
||||||
prevFieldEnd, gDataLayout->getABITypeAlignment(C->getType()));
|
#if LDC_LLVM_VER >= 309
|
||||||
|
llvm::alignTo
|
||||||
|
#else
|
||||||
|
llvm::RoundUpToAlignment
|
||||||
|
#endif
|
||||||
|
(prevFieldEnd, gDataLayout->getABITypeAlignment(C->getType()));
|
||||||
|
|
||||||
const uint64_t paddingBytes = fieldStart - prevFieldEnd;
|
const uint64_t paddingBytes = fieldStart - prevFieldEnd;
|
||||||
if (paddingBytes) {
|
if (paddingBytes) {
|
||||||
llvm::Type *const padding = llvm::ArrayType::get(
|
llvm::Type *const padding = llvm::ArrayType::get(
|
||||||
|
|
|
@ -653,34 +653,23 @@ static void buildRuntimeModule() {
|
||||||
{objectTy});
|
{objectTy});
|
||||||
|
|
||||||
// void _d_dso_registry(CompilerDSOData* data)
|
// void _d_dso_registry(CompilerDSOData* data)
|
||||||
if (global.params.targetTriple->isOSLinux() || global.params.targetTriple->isOSFreeBSD() ||
|
llvm::StringRef fname("_d_dso_registry");
|
||||||
#if LDC_LLVM_VER > 305
|
|
||||||
global.params.targetTriple->isOSNetBSD() || global.params.targetTriple->isOSOpenBSD() ||
|
|
||||||
global.params.targetTriple->isOSDragonFly()
|
|
||||||
#else
|
|
||||||
global.params.targetTriple->getOS() == llvm::Triple::NetBSD ||
|
|
||||||
global.params.targetTriple->getOS() == llvm::Triple::OpenBSD ||
|
|
||||||
global.params.targetTriple->getOS() == llvm::Triple::DragonFly
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
llvm::StringRef fname("_d_dso_registry");
|
|
||||||
|
|
||||||
LLType *LLvoidTy = LLType::getVoidTy(gIR->context());
|
LLType *LLvoidTy = LLType::getVoidTy(gIR->context());
|
||||||
LLType *LLvoidPtrPtrTy = getPtrToType(getPtrToType(LLvoidTy));
|
LLType *LLvoidPtrPtrTy = getPtrToType(getPtrToType(LLvoidTy));
|
||||||
LLType *moduleInfoPtrPtrTy =
|
LLType *moduleInfoPtrPtrTy =
|
||||||
getPtrToType(getPtrToType(DtoType(Module::moduleinfo->type)));
|
getPtrToType(getPtrToType(DtoType(Module::moduleinfo->type)));
|
||||||
|
|
||||||
llvm::StructType *dsoDataTy =
|
llvm::StructType *dsoDataTy =
|
||||||
llvm::StructType::get(DtoSize_t(), // version
|
llvm::StructType::get(DtoSize_t(), // version
|
||||||
LLvoidPtrPtrTy, // slot
|
LLvoidPtrPtrTy, // slot
|
||||||
moduleInfoPtrPtrTy, // _minfo_beg
|
moduleInfoPtrPtrTy, // _minfo_beg
|
||||||
moduleInfoPtrPtrTy, // _minfo_end
|
moduleInfoPtrPtrTy, // _minfo_end
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
llvm::Type *types[] = {getPtrToType(dsoDataTy)};
|
llvm::Type *types[] = {getPtrToType(dsoDataTy)};
|
||||||
llvm::FunctionType *fty = llvm::FunctionType::get(LLvoidTy, types, false);
|
llvm::FunctionType *fty = llvm::FunctionType::get(LLvoidTy, types, false);
|
||||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -71,7 +71,17 @@ unsigned Target::critsecsize() {
|
||||||
if (global.params.targetTriple->isOSWindows()) {
|
if (global.params.targetTriple->isOSWindows()) {
|
||||||
return global.params.is64bit ? 40 : 24;
|
return global.params.is64bit ? 40 : 24;
|
||||||
}
|
}
|
||||||
if (global.params.targetTriple->getOS() == llvm::Triple::FreeBSD) {
|
if (global.params.targetTriple->isOSFreeBSD() ||
|
||||||
|
#if LDC_LLVM_VER > 305
|
||||||
|
global.params.targetTriple->isOSNetBSD() ||
|
||||||
|
global.params.targetTriple->isOSOpenBSD() ||
|
||||||
|
global.params.targetTriple->isOSDragonFly()
|
||||||
|
#else
|
||||||
|
global.params.targetTriple->getOS() == llvm::Triple::NetBSD ||
|
||||||
|
global.params.targetTriple->getOS() == llvm::Triple::OpenBSD ||
|
||||||
|
global.params.targetTriple->getOS() == llvm::Triple::DragonFly
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
return sizeof(size_t);
|
return sizeof(size_t);
|
||||||
}
|
}
|
||||||
return sizeof(pthread_mutex_t);
|
return sizeof(pthread_mutex_t);
|
||||||
|
|
|
@ -505,7 +505,7 @@ void DtoAlignedStore(LLValue *src, LLValue *dst) {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
LLValue *DtoBitCast(LLValue *v, LLType *t, const char *name) {
|
LLValue *DtoBitCast(LLValue *v, LLType *t, const llvm::Twine &name) {
|
||||||
if (v->getType() == t) {
|
if (v->getType() == t) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -668,8 +668,18 @@ LLStructType *DtoMutexType() {
|
||||||
return mutex;
|
return mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FreeBSD
|
// FreeBSD, NetBSD, OpenBSD, DragonFly
|
||||||
if (global.params.targetTriple->getOS() == llvm::Triple::FreeBSD) {
|
if (global.params.targetTriple->isOSFreeBSD() ||
|
||||||
|
#if LDC_LLVM_VER > 305
|
||||||
|
global.params.targetTriple->isOSNetBSD() ||
|
||||||
|
global.params.targetTriple->isOSOpenBSD() ||
|
||||||
|
global.params.targetTriple->isOSDragonFly()
|
||||||
|
#else
|
||||||
|
global.params.targetTriple->getOS() == llvm::Triple::NetBSD ||
|
||||||
|
global.params.targetTriple->getOS() == llvm::Triple::OpenBSD ||
|
||||||
|
global.params.targetTriple->getOS() == llvm::Triple::DragonFly
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
// Just a pointer
|
// Just a pointer
|
||||||
return LLStructType::get(gIR->context(), DtoSize_t());
|
return LLStructType::get(gIR->context(), DtoSize_t());
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ void DtoStore(LLValue *src, LLValue *dst);
|
||||||
void DtoVolatileStore(LLValue *src, LLValue *dst);
|
void DtoVolatileStore(LLValue *src, LLValue *dst);
|
||||||
void DtoStoreZextI8(LLValue *src, LLValue *dst);
|
void DtoStoreZextI8(LLValue *src, LLValue *dst);
|
||||||
void DtoAlignedStore(LLValue *src, LLValue *dst);
|
void DtoAlignedStore(LLValue *src, LLValue *dst);
|
||||||
LLValue *DtoBitCast(LLValue *v, LLType *t, const char *name = "");
|
LLValue *DtoBitCast(LLValue *v, LLType *t, const llvm::Twine &name = "");
|
||||||
LLConstant *DtoBitCast(LLConstant *v, LLType *t);
|
LLConstant *DtoBitCast(LLConstant *v, LLType *t);
|
||||||
LLValue *DtoInsertValue(LLValue *aggr, LLValue *v, unsigned idx,
|
LLValue *DtoInsertValue(LLValue *aggr, LLValue *v, unsigned idx,
|
||||||
const char *name = "");
|
const char *name = "");
|
||||||
|
|
|
@ -16,11 +16,8 @@
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "ir/irtype.h"
|
#include "ir/irtype.h"
|
||||||
|
|
||||||
// This code uses llvm::getGlobalContext() as these functions are invoked before
|
// These functions use llvm::getGlobalContext() as they are invoked before gIR
|
||||||
// gIR is set.
|
// is set.
|
||||||
// ... thus it segfaults on gIR==NULL
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
IrType::IrType(Type *dt, LLType *lt) : dtype(dt), type(lt) {
|
IrType::IrType(Type *dt, LLType *lt) : dtype(dt), type(lt) {
|
||||||
assert(dt && "null D Type");
|
assert(dt && "null D Type");
|
||||||
|
@ -28,36 +25,27 @@ IrType::IrType(Type *dt, LLType *lt) : dtype(dt), type(lt) {
|
||||||
assert(!dt->ctype && "already has IrType");
|
assert(!dt->ctype && "already has IrType");
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
IrFuncTy &IrType::getIrFuncTy() {
|
IrFuncTy &IrType::getIrFuncTy() {
|
||||||
llvm_unreachable("cannot get IrFuncTy from non lazy/function/delegate");
|
llvm_unreachable("cannot get IrFuncTy from non lazy/function/delegate");
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
IrTypeBasic::IrTypeBasic(Type *dt) : IrType(dt, basic2llvm(dt)) {}
|
IrTypeBasic::IrTypeBasic(Type *dt) : IrType(dt, basic2llvm(dt)) {}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
IrTypeBasic *IrTypeBasic::get(Type *dt) {
|
IrTypeBasic *IrTypeBasic::get(Type *dt) {
|
||||||
auto t = new IrTypeBasic(dt);
|
auto t = new IrTypeBasic(dt);
|
||||||
dt->ctype = t;
|
dt->ctype = t;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
LLType *IrTypeBasic::getComplexType(llvm::LLVMContext &ctx, LLType *type) {
|
LLType *IrTypeBasic::getComplexType(llvm::LLVMContext &ctx, LLType *type) {
|
||||||
llvm::Type *types[] = {type, type};
|
llvm::Type *types[] = {type, type};
|
||||||
return llvm::StructType::get(ctx, types, false);
|
return llvm::StructType::get(ctx, types, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
namespace {
|
||||||
|
llvm::Type *getReal80Type(llvm::LLVMContext &ctx) {
|
||||||
static inline llvm::Type *getReal80Type(llvm::LLVMContext &ctx) {
|
|
||||||
llvm::Triple::ArchType const a = global.params.targetTriple->getArch();
|
llvm::Triple::ArchType const a = global.params.targetTriple->getArch();
|
||||||
bool const anyX86 = (a == llvm::Triple::x86) || (a == llvm::Triple::x86_64);
|
bool const anyX86 = (a == llvm::Triple::x86) || (a == llvm::Triple::x86_64);
|
||||||
|
|
||||||
|
@ -68,8 +56,7 @@ static inline llvm::Type *getReal80Type(llvm::LLVMContext &ctx) {
|
||||||
|
|
||||||
return llvm::Type::getDoubleTy(ctx);
|
return llvm::Type::getDoubleTy(ctx);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
llvm::Type *IrTypeBasic::basic2llvm(Type *t) {
|
llvm::Type *IrTypeBasic::basic2llvm(Type *t) {
|
||||||
llvm::LLVMContext &ctx = llvm::getGlobalContext();
|
llvm::LLVMContext &ctx = llvm::getGlobalContext();
|
||||||
|
@ -129,14 +116,10 @@ llvm::Type *IrTypeBasic::basic2llvm(Type *t) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
IrTypePointer::IrTypePointer(Type *dt, LLType *lt) : IrType(dt, lt) {}
|
IrTypePointer::IrTypePointer(Type *dt, LLType *lt) : IrType(dt, lt) {}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
IrTypePointer *IrTypePointer::get(Type *dt) {
|
IrTypePointer *IrTypePointer::get(Type *dt) {
|
||||||
assert(!dt->ctype);
|
assert(!dt->ctype);
|
||||||
assert((dt->ty == Tpointer || dt->ty == Tnull) && "not pointer/null type");
|
assert((dt->ty == Tpointer || dt->ty == Tnull) && "not pointer/null type");
|
||||||
|
@ -159,38 +142,31 @@ IrTypePointer *IrTypePointer::get(Type *dt) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
IrTypeSArray::IrTypeSArray(Type *dt) : IrType(dt, sarray2llvm(dt)) {}
|
IrTypeSArray::IrTypeSArray(Type *dt, LLType *lt) : IrType(dt, lt) {}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
IrTypeSArray *IrTypeSArray::get(Type *dt) {
|
IrTypeSArray *IrTypeSArray::get(Type *dt) {
|
||||||
auto t = new IrTypeSArray(dt);
|
assert(!dt->ctype);
|
||||||
dt->ctype = t;
|
assert(dt->ty == Tsarray && "not static array type");
|
||||||
return t;
|
|
||||||
|
LLType *elemType = DtoMemType(dt->nextOf());
|
||||||
|
|
||||||
|
// We might have already built the type during DtoMemType e.g. as part of a
|
||||||
|
// forward reference in a struct.
|
||||||
|
if (!dt->ctype) {
|
||||||
|
TypeSArray *tsa = static_cast<TypeSArray *>(dt);
|
||||||
|
uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger());
|
||||||
|
dt->ctype = new IrTypeSArray(dt, llvm::ArrayType::get(elemType, dim));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt->ctype->isSArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
llvm::Type *IrTypeSArray::sarray2llvm(Type *t) {
|
|
||||||
assert(t->ty == Tsarray && "not static array type");
|
|
||||||
TypeSArray *tsa = static_cast<TypeSArray *>(t);
|
|
||||||
uint64_t dim = static_cast<uint64_t>(tsa->dim->toUInteger());
|
|
||||||
LLType *elemType = DtoMemType(t->nextOf());
|
|
||||||
return llvm::ArrayType::get(elemType, dim);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
IrTypeArray::IrTypeArray(Type *dt, LLType *lt) : IrType(dt, lt) {}
|
IrTypeArray::IrTypeArray(Type *dt, LLType *lt) : IrType(dt, lt) {}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
IrTypeArray *IrTypeArray::get(Type *dt) {
|
IrTypeArray *IrTypeArray::get(Type *dt) {
|
||||||
assert(!dt->ctype);
|
assert(!dt->ctype);
|
||||||
assert(dt->ty == Tarray && "not dynamic array type");
|
assert(dt->ty == Tarray && "not dynamic array type");
|
||||||
|
@ -208,22 +184,20 @@ IrTypeArray *IrTypeArray::get(Type *dt) {
|
||||||
return dt->ctype->isArray();
|
return dt->ctype->isArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
IrTypeVector::IrTypeVector(Type *dt) : IrType(dt, vector2llvm(dt)) {}
|
IrTypeVector::IrTypeVector(Type *dt, llvm::Type *lt) : IrType(dt, lt) {}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
IrTypeVector *IrTypeVector::get(Type *dt) {
|
IrTypeVector *IrTypeVector::get(Type *dt) {
|
||||||
auto t = new IrTypeVector(dt);
|
LLType *lt = vector2llvm(dt);
|
||||||
dt->ctype = t;
|
// Could have already built the type as part of a struct forward reference,
|
||||||
return t;
|
// just as for pointers and arrays.
|
||||||
|
if (!dt->ctype) {
|
||||||
|
dt->ctype = new IrTypeVector(dt, lt);
|
||||||
|
}
|
||||||
|
return dt->ctype->isVector();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
llvm::Type *IrTypeVector::vector2llvm(Type *dt) {
|
llvm::Type *IrTypeVector::vector2llvm(Type *dt) {
|
||||||
assert(dt->ty == Tvector && "not vector type");
|
assert(dt->ty == Tvector && "not vector type");
|
||||||
TypeVector *tv = static_cast<TypeVector *>(dt);
|
TypeVector *tv = static_cast<TypeVector *>(dt);
|
||||||
|
@ -233,5 +207,3 @@ llvm::Type *IrTypeVector::vector2llvm(Type *dt) {
|
||||||
LLType *elemType = DtoMemType(tsa->next);
|
LLType *elemType = DtoMemType(tsa->next);
|
||||||
return llvm::VectorType::get(elemType, dim);
|
return llvm::VectorType::get(elemType, dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
27
ir/irtype.h
27
ir/irtype.h
|
@ -46,17 +46,17 @@ class IrTypeVector;
|
||||||
///
|
///
|
||||||
/// Derived classes should be created using their static get() methods, which
|
/// Derived classes should be created using their static get() methods, which
|
||||||
/// makes sure that uniqueness is preserved in the face of forward references.
|
/// makes sure that uniqueness is preserved in the face of forward references.
|
||||||
/// Note that the get() methods expect the IrType of the passed type/symbol to
|
|
||||||
/// be not yet set.
|
|
||||||
///
|
///
|
||||||
/// This could be altered to just return the existing IrType in order to bring
|
/// Note that the get() methods expect the IrType of the passed type/symbol not
|
||||||
/// the API entirely in line with the LLVM type get() methods. It has not been
|
/// to be set yet. Another option would be to just return the existing IrType
|
||||||
/// changed so far since currently all clients use the DtoType wrapper rather
|
/// in such cases. This would bring the API more in line with the llvm::Type
|
||||||
/// than handling IrType instances directly, and keeping it this way allows to
|
/// get() functions. Currently all clients use the DtoType() wrapper anyway
|
||||||
/// easily check for uniqueness violations in the face of forward references.
|
/// instead of directly handling IrType instances, so keeping the assertions
|
||||||
/// TODO: Implement the described changes (now that the forward reference
|
/// allows us to check for any uniqueness violations that might have slipped
|
||||||
/// handling logic seems to work correctly) and get rid of the "no-op" DtoType
|
/// through.
|
||||||
/// calls in IrAggr, ... that only exist for their side effect.
|
// TODO: Implement the described changes (now that the forward reference
|
||||||
|
// handling logic seems to work correctly) and get rid of the "no-op" DtoType
|
||||||
|
// calls in IrAggr, ... that only exist for their side effect.
|
||||||
class IrType {
|
class IrType {
|
||||||
public:
|
public:
|
||||||
virtual ~IrType() = default;
|
virtual ~IrType() = default;
|
||||||
|
@ -150,10 +150,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
///
|
///
|
||||||
explicit IrTypeSArray(Type *dt);
|
IrTypeSArray(Type *dt, LLType *lt);
|
||||||
|
|
||||||
///
|
|
||||||
static llvm::Type *sarray2llvm(Type *t);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -185,7 +182,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
///
|
///
|
||||||
explicit IrTypeVector(Type *dt);
|
explicit IrTypeVector(Type *dt, llvm::Type *lt);
|
||||||
|
|
||||||
static llvm::Type *vector2llvm(Type *dt);
|
static llvm::Type *vector2llvm(Type *dt);
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,9 +26,12 @@ IrTypeFunction *IrTypeFunction::get(Type *dt) {
|
||||||
IrFuncTy irFty;
|
IrFuncTy irFty;
|
||||||
llvm::Type *lt = DtoFunctionType(dt, irFty, nullptr, nullptr);
|
llvm::Type *lt = DtoFunctionType(dt, irFty, nullptr, nullptr);
|
||||||
|
|
||||||
auto result = new IrTypeFunction(dt, lt, irFty);
|
// Could have already built the type as part of a struct forward reference,
|
||||||
dt->ctype = result;
|
// just as for pointers and arrays.
|
||||||
return result;
|
if (!dt->ctype) {
|
||||||
|
dt->ctype = new IrTypeFunction(dt, lt, irFty);
|
||||||
|
}
|
||||||
|
return dt->ctype->isFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -47,7 +50,10 @@ IrTypeDelegate *IrTypeDelegate::get(Type *t) {
|
||||||
llvm::Type *types[] = {getVoidPtrType(), getPtrToType(ltf)};
|
llvm::Type *types[] = {getVoidPtrType(), getPtrToType(ltf)};
|
||||||
LLStructType *lt = LLStructType::get(gIR->context(), types, false);
|
LLStructType *lt = LLStructType::get(gIR->context(), types, false);
|
||||||
|
|
||||||
auto result = new IrTypeDelegate(t, lt, irFty);
|
// Could have already built the type as part of a struct forward reference,
|
||||||
t->ctype = result;
|
// just as for pointers and arrays.
|
||||||
return result;
|
if (!t->ctype) {
|
||||||
|
t->ctype = new IrTypeDelegate(t, lt, irFty);
|
||||||
|
}
|
||||||
|
return t->ctype->isDelegate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ else()
|
||||||
endif()
|
endif()
|
||||||
file(GLOB_RECURSE CORE_D_UNIX ${RUNTIME_DIR}/src/core/sys/posix/*.d)
|
file(GLOB_RECURSE CORE_D_UNIX ${RUNTIME_DIR}/src/core/sys/posix/*.d)
|
||||||
file(GLOB_RECURSE CORE_D_FREEBSD ${RUNTIME_DIR}/src/core/sys/freebsd/*.d)
|
file(GLOB_RECURSE CORE_D_FREEBSD ${RUNTIME_DIR}/src/core/sys/freebsd/*.d)
|
||||||
|
file(GLOB_RECURSE CORE_D_NETBSD ${RUNTIME_DIR}/src/core/sys/netbsd/*.d)
|
||||||
file(GLOB_RECURSE CORE_D_LINUX ${RUNTIME_DIR}/src/core/sys/linux/*.d)
|
file(GLOB_RECURSE CORE_D_LINUX ${RUNTIME_DIR}/src/core/sys/linux/*.d)
|
||||||
file(GLOB_RECURSE CORE_D_OSX ${RUNTIME_DIR}/src/core/sys/osx/*.d)
|
file(GLOB_RECURSE CORE_D_OSX ${RUNTIME_DIR}/src/core/sys/osx/*.d)
|
||||||
file(GLOB_RECURSE CORE_D_SOLARIS ${RUNTIME_DIR}/src/core/sys/solaris/*.d)
|
file(GLOB_RECURSE CORE_D_SOLARIS ${RUNTIME_DIR}/src/core/sys/solaris/*.d)
|
||||||
|
@ -95,6 +96,9 @@ if(UNIX)
|
||||||
if(${CMAKE_SYSTEM} MATCHES "FreeBSD")
|
if(${CMAKE_SYSTEM} MATCHES "FreeBSD")
|
||||||
list(APPEND CORE_D_SYS ${CORE_D_FREEBSD})
|
list(APPEND CORE_D_SYS ${CORE_D_FREEBSD})
|
||||||
endif()
|
endif()
|
||||||
|
if(${CMAKE_SYSTEM} MATCHES "NetBSD")
|
||||||
|
list(APPEND CORE_D_SYS ${CORE_D_NETBSD})
|
||||||
|
endif()
|
||||||
if(${CMAKE_SYSTEM} MATCHES "Linux")
|
if(${CMAKE_SYSTEM} MATCHES "Linux")
|
||||||
list(APPEND CORE_D_SYS ${CORE_D_LINUX})
|
list(APPEND CORE_D_SYS ${CORE_D_LINUX})
|
||||||
endif()
|
endif()
|
||||||
|
@ -214,11 +218,31 @@ configure_file(${PROJECT_PARENT_DIR}/${LDC_EXE}_install.conf.in ${PROJECT_BINARY
|
||||||
# druntime/Phobos compilation helpers.
|
# druntime/Phobos compilation helpers.
|
||||||
#
|
#
|
||||||
|
|
||||||
set(GCCBUILTINS "${PROJECT_BINARY_DIR}/gccbuiltins_x86.di")
|
set(GCCBUILTINS "")
|
||||||
add_custom_command(
|
function(gen_gccbuiltins name)
|
||||||
OUTPUT ${GCCBUILTINS}
|
set(module "gccbuiltins_${name}.di")
|
||||||
COMMAND gen_gccbuiltins ${GCCBUILTINS} "x86"
|
if (GCCBUILTINS STREQUAL "")
|
||||||
)
|
set(GCCBUILTINS "${module}" PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(GCCBUILTINS "${GCCBUILTINS};${module}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${module}
|
||||||
|
COMMAND gen_gccbuiltins ${module} "${name}"
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
set(target_arch "AArch64;ARM;Mips;PowerPC;SystemZ;X86")
|
||||||
|
set(target_name "aarch64;arm;mips;ppc;s390;x86")
|
||||||
|
|
||||||
|
foreach(target ${LLVM_TARGETS_TO_BUILD})
|
||||||
|
list(FIND target_arch ${target} idx)
|
||||||
|
if(idx GREATER -1)
|
||||||
|
list(GET target_name ${idx} name)
|
||||||
|
gen_gccbuiltins(${name})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
# Always build zlib and other C parts of the runtime in release mode, regardless
|
# Always build zlib and other C parts of the runtime in release mode, regardless
|
||||||
# of what the user chose for LDC itself.
|
# of what the user chose for LDC itself.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2cdd96be5070cfabf5cf2724a8dea46cd3922999
|
Subproject commit 65ea3f07dee9132c0aa8344d612e19e520e600df
|
|
@ -1 +1 @@
|
||||||
Subproject commit 74730f61530d4d653b047bb02948e15064a214c1
|
Subproject commit 83fbcc4b18527c2a7c8181a51098f215e4a14b10
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2c1a5ed7603f809eab6f565e9ee924cc0f5e1005
|
Subproject commit 25c2a1be486b6cb60584f5a74fa978450559dbbd
|
Loading…
Add table
Add a link
Reference in a new issue