From a2808ec46e0636260fb64e2b9a60ade1f537cde6 Mon Sep 17 00:00:00 2001 From: Martin Date: Sun, 8 Apr 2018 01:02:55 +0200 Subject: [PATCH 1/9] 64-bit OSX: Mangle [u]long as C++ [u]int64_t This is a breaking ABI change and affects LDC itself as mixed D/C++ code base. So we now need to check the front-end version of the D host compiler and adapt the corresponding C++ types accordingly. --- CMakeLists.txt | 1 + cmake/Modules/FindDCompiler.cmake | 4 ++++ dmd/globals.h | 6 ++++++ dmd/identifier.h | 2 +- dmd/root/rmem.h | 15 ++++++++------- driver/cache_pruning.h | 10 +++------- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6d1f71299f..93ea10b07b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,6 +417,7 @@ append("-DOPAQUE_VTBLS" LDC_CXXFLAGS) append("\"-DLDC_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}\"" LDC_CXXFLAGS) append("-DLDC_LLVM_VER=${LDC_LLVM_VER}" LDC_CXXFLAGS) append("\"-DLDC_LIBDIR_SUFFIX=\\\"${LIB_SUFFIX}\\\"\"" LDC_CXXFLAGS) +append("-DLDC_HOST_FE_VER=${D_COMPILER_FE_VERSION}" LDC_CXXFLAGS) if(GENERATE_OFFTI) append("-DGENERATE_OFFTI" LDC_CXXFLAGS) diff --git a/cmake/Modules/FindDCompiler.cmake b/cmake/Modules/FindDCompiler.cmake index 61c2277b520..8c19d841e1f 100644 --- a/cmake/Modules/FindDCompiler.cmake +++ b/cmake/Modules/FindDCompiler.cmake @@ -8,6 +8,7 @@ # D_COMPILER_FLAGS - D compiler flags (could be passed in the DMD environment variable) # D_COMPILER_ID = {"DigitalMars", "LDMD", "LDC", "GDC"} # D_COMPILER_VERSION_STRING - String containing the compiler version, e.g. "DMD64 D Compiler v2.070.2" +# D_COMPILER_FE_VERSION - compiler front-end version, e.g. "2070" # D_COMPILER_DMD_COMPAT - true if the D compiler cmdline interface is compatible with DMD @@ -64,6 +65,8 @@ if (D_COMPILER) OUTPUT_VARIABLE D_COMPILER_VERSION_STRING ERROR_VARIABLE D_COMPILER_VERSION_STRING ERROR_QUIET) + string(REGEX MATCH " (D Compiler|based on DMD) v([0-9]+)\\.([0-9]+)" D_COMPILER_FE_VERSION "${D_COMPILER_VERSION_STRING}") + math(EXPR D_COMPILER_FE_VERSION ${CMAKE_MATCH_2}*1000+${CMAKE_MATCH_3}) # e.g., 2079 string(REGEX MATCH "^[^\r\n:]*" D_COMPILER_VERSION_STRING "${D_COMPILER_VERSION_STRING}") endif() @@ -71,6 +74,7 @@ endif() if (D_COMPILER_FOUND) message(STATUS "Found host D compiler ${D_COMPILER}, with default flags '${D_COMPILER_FLAGS}'") message(STATUS "Host D compiler version: ${D_COMPILER_VERSION_STRING}") + message(STATUS "Host D compiler front-end version: ${D_COMPILER_FE_VERSION}") else() message(FATAL_ERROR "No D compiler found! Try setting the 'D_COMPILER' variable or 'DMD' environment variable.") endif() diff --git a/dmd/globals.h b/dmd/globals.h index aca6f640610..d074d157b70 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -330,6 +330,11 @@ struct Global extern Global global; +#if LDC_HOST_FE_VER >= 2079 +typedef uint64_t dinteger_t; +typedef int64_t sinteger_t; +typedef uint64_t uinteger_t; +#else // Because int64_t and friends may be any integral type of the // correct size, we have to explicitly ask for the correct // integer type to get the correct mangling with dmd @@ -346,6 +351,7 @@ typedef unsigned long long dinteger_t; typedef long long sinteger_t; typedef unsigned long long uinteger_t; #endif +#endif typedef int8_t d_int8; typedef uint8_t d_uns8; diff --git a/dmd/identifier.h b/dmd/identifier.h index 8c47572e389..93bc099155b 100644 --- a/dmd/identifier.h +++ b/dmd/identifier.h @@ -38,7 +38,7 @@ class Identifier : public RootObject static StringTable stringtable; static Identifier *generateId(const char *prefix); static Identifier *generateId(const char *prefix, size_t i); - static Identifier *idPool(const char *s, size_t len); + static Identifier *idPool(const char *s, d_size_t len); static inline Identifier *idPool(const char *s) { diff --git a/dmd/root/rmem.h b/dmd/root/rmem.h index ca8452379eb..0a52b627a13 100644 --- a/dmd/root/rmem.h +++ b/dmd/root/rmem.h @@ -10,15 +10,16 @@ #ifndef ROOT_MEM_H #define ROOT_MEM_H -#include // for size_t +#include -#if __APPLE__ && __i386__ - /* size_t is 'unsigned long', which makes it mangle differently - * than D's 'uint' - */ - typedef unsigned d_size_t; +#if __LP64__ || _M_X64 +#if LDC_HOST_FE_VER >= 2079 || _M_X64 +typedef uint64_t d_size_t; #else - typedef size_t d_size_t; +typedef unsigned long d_size_t; +#endif +#else +typedef uint32_t d_size_t; #endif struct Mem diff --git a/driver/cache_pruning.h b/driver/cache_pruning.h index 0bdff0f1859..a19fb2794e7 100644 --- a/driver/cache_pruning.h +++ b/driver/cache_pruning.h @@ -10,14 +10,10 @@ #ifndef LDC_DRIVER_IR2OBJ_CACHE_PRUNING_H #define LDC_DRIVER_IR2OBJ_CACHE_PRUNING_H -#if __LP64__ -using d_ulong = unsigned long; -#else -using d_ulong = unsigned long long; -#endif +#include "globals.h" -void pruneCache(const char *cacheDirectoryPtr, size_t cacheDirectoryLen, +void pruneCache(const char *cacheDirectoryPtr, d_size_t cacheDirectoryLen, uint32_t pruneIntervalSeconds, uint32_t expireIntervalSeconds, - d_ulong sizeLimitBytes, uint32_t sizeLimitPercentage); + uinteger_t sizeLimitBytes, uint32_t sizeLimitPercentage); #endif From 7426d1fdde0696011e79b604270910d9a7840820 Mon Sep 17 00:00:00 2001 From: Martin Date: Sun, 8 Apr 2018 18:28:36 +0200 Subject: [PATCH 2/9] dmd-testsuite: Add interop tests for C++ long and size_t --- tests/d2/dmd-testsuite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite index 4f08cfc4e17..025581a647d 160000 --- a/tests/d2/dmd-testsuite +++ b/tests/d2/dmd-testsuite @@ -1 +1 @@ -Subproject commit 4f08cfc4e17bc0b2d5e56eb35c0a1f5de26674ee +Subproject commit 025581a647d36a3ff9edc7178d04f5f125995948 From 6b0ca0e194795d2b31b61f81ed44867618fd8b9b Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 9 Apr 2018 21:24:58 +0200 Subject: [PATCH 3/9] 64-bit OSX: Revert to mangling (u)long as C++ (unsigned) long Primarily not to break size_t interop. A size_t is probably much more frequently used than `(unsigned) long long` (which Apple sadly chose for their C++ `(u)int64_t`). --- dmd/globals.h | 6 ------ dmd/identifier.h | 2 +- dmd/root/rmem.h | 15 +++++++-------- driver/cache_pruning.h | 10 +++++++--- gen/target.cpp | 5 +++-- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/dmd/globals.h b/dmd/globals.h index d074d157b70..aca6f640610 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -330,11 +330,6 @@ struct Global extern Global global; -#if LDC_HOST_FE_VER >= 2079 -typedef uint64_t dinteger_t; -typedef int64_t sinteger_t; -typedef uint64_t uinteger_t; -#else // Because int64_t and friends may be any integral type of the // correct size, we have to explicitly ask for the correct // integer type to get the correct mangling with dmd @@ -351,7 +346,6 @@ typedef unsigned long long dinteger_t; typedef long long sinteger_t; typedef unsigned long long uinteger_t; #endif -#endif typedef int8_t d_int8; typedef uint8_t d_uns8; diff --git a/dmd/identifier.h b/dmd/identifier.h index 93bc099155b..8c47572e389 100644 --- a/dmd/identifier.h +++ b/dmd/identifier.h @@ -38,7 +38,7 @@ class Identifier : public RootObject static StringTable stringtable; static Identifier *generateId(const char *prefix); static Identifier *generateId(const char *prefix, size_t i); - static Identifier *idPool(const char *s, d_size_t len); + static Identifier *idPool(const char *s, size_t len); static inline Identifier *idPool(const char *s) { diff --git a/dmd/root/rmem.h b/dmd/root/rmem.h index 0a52b627a13..ca8452379eb 100644 --- a/dmd/root/rmem.h +++ b/dmd/root/rmem.h @@ -10,16 +10,15 @@ #ifndef ROOT_MEM_H #define ROOT_MEM_H -#include +#include // for size_t -#if __LP64__ || _M_X64 -#if LDC_HOST_FE_VER >= 2079 || _M_X64 -typedef uint64_t d_size_t; +#if __APPLE__ && __i386__ + /* size_t is 'unsigned long', which makes it mangle differently + * than D's 'uint' + */ + typedef unsigned d_size_t; #else -typedef unsigned long d_size_t; -#endif -#else -typedef uint32_t d_size_t; + typedef size_t d_size_t; #endif struct Mem diff --git a/driver/cache_pruning.h b/driver/cache_pruning.h index a19fb2794e7..0bdff0f1859 100644 --- a/driver/cache_pruning.h +++ b/driver/cache_pruning.h @@ -10,10 +10,14 @@ #ifndef LDC_DRIVER_IR2OBJ_CACHE_PRUNING_H #define LDC_DRIVER_IR2OBJ_CACHE_PRUNING_H -#include "globals.h" +#if __LP64__ +using d_ulong = unsigned long; +#else +using d_ulong = unsigned long long; +#endif -void pruneCache(const char *cacheDirectoryPtr, d_size_t cacheDirectoryLen, +void pruneCache(const char *cacheDirectoryPtr, size_t cacheDirectoryLen, uint32_t pruneIntervalSeconds, uint32_t expireIntervalSeconds, - uinteger_t sizeLimitBytes, uint32_t sizeLimitPercentage); + d_ulong sizeLimitBytes, uint32_t sizeLimitPercentage); #endif diff --git a/gen/target.cpp b/gen/target.cpp index 6eec49d28b9..0a9546c917e 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -44,8 +44,9 @@ void Target::_init() { classinfosize = 0; // unused maxStaticDataSize = std::numeric_limits::max(); - int64Mangle = triple.isOSDarwin() ? 'x' : 'l'; - uint64Mangle = triple.isOSDarwin() ? 'y' : 'm'; + // These C++ mangling characters are only used for 64-bit POSIX targets. + int64Mangle = 'l'; // C++ long + uint64Mangle = 'm'; // C++ unsigned long // {Float,Double,Real}Properties have been initialized with the D host // compiler's properties. From d983cd01c5f425ba341276fa374ef7b77b55cd3a Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 9 Apr 2018 21:04:32 +0200 Subject: [PATCH 4/9] Add support for new magic structs __c_(u)longlong To be mangled as C++ (unsigned) long long. For MSVC targets, D (u)long is C++-mangled as (unsigned) long long, so there's no need for these magic structs. For 32-bit POSIX targets, D (u)long is also a natural fit already. For 64-bit POSIX targets however, D (u)long is C++-mangled as (unsigned) long, so there's no corresponding D type, and these magic structs are needed. Especially since macOS defines `int64_t` as `long long`, unlike Linux (`long`). --- dmd/cppmangle.d | 6 +++++- dmd/cppmanglewin.d | 21 ++++++++++++--------- dmd/id.d | 2 ++ dmd/id.h | 2 ++ gen/abi.cpp | 1 + gen/abi.h | 4 ++-- 6 files changed, 24 insertions(+), 12 deletions(-) diff --git a/dmd/cppmangle.d b/dmd/cppmangle.d index 85122773760..18d4f344f28 100644 --- a/dmd/cppmangle.d +++ b/dmd/cppmangle.d @@ -943,7 +943,7 @@ public: if (t.isImmutable() || t.isShared()) return error(t); - /* __c_long and __c_ulong get special mangling + /* magic structs __c_(u)long(long) get special mangling */ const id = t.sym.ident; //printf("struct id = '%s'\n", id.toChars()); @@ -951,6 +951,10 @@ public: return writeBasicType(t, 0, 'l'); else if (id == Id.__c_ulong) return writeBasicType(t, 0, 'm'); + else if (id == Id.__c_longlong) + return writeBasicType(t, 0, 'x'); + else if (id == Id.__c_ulonglong) + return writeBasicType(t, 0, 'y'); //printf("TypeStruct %s\n", t.toChars()); doSymbol(t); diff --git a/dmd/cppmanglewin.d b/dmd/cppmanglewin.d index e411c8256a2..0f89872951b 100644 --- a/dmd/cppmanglewin.d +++ b/dmd/cppmanglewin.d @@ -374,16 +374,18 @@ public: override void visit(TypeStruct type) { const id = type.sym.ident; - char c; + string c; if (id == Id.__c_long_double) - c = 'O'; // VC++ long double + c = "O"; // VC++ long double else if (id == Id.__c_long) - c = 'J'; // VC++ long + c = "J"; // VC++ long else if (id == Id.__c_ulong) - c = 'K'; // VC++ unsigned long - else - c = 0; - if (c) + c = "K"; // VC++ unsigned long + else if (id == Id.__c_longlong) + c = "_J"; // VC++ long long + else if (id == Id.__c_ulonglong) + c = "_K"; // VC++ unsigned long long + if (c.length) { if (type.isImmutable() || type.isShared()) { @@ -396,7 +398,7 @@ public: return; } mangleModifier(type); - buf.writeByte(c); + buf.writestring(c); } else { @@ -1025,7 +1027,8 @@ private: if (rettype.ty == Tstruct || rettype.ty == Tenum) { const id = rettype.toDsymbol(null).ident; - if (id != Id.__c_long_double && id != Id.__c_long && id != Id.__c_ulong) + if (id != Id.__c_long_double && id != Id.__c_long && id != Id.__c_ulong && + id != Id.__c_longlong && id != Id.__c_ulonglong) { tmp.buf.writeByte('?'); tmp.buf.writeByte('A'); diff --git a/dmd/id.d b/dmd/id.d index b7d2d435a07..dd6f9dfd7e1 100644 --- a/dmd/id.d +++ b/dmd/id.d @@ -111,6 +111,8 @@ immutable Msgtable[] msgtable = { "gate", "__gate" }, { "__c_long" }, { "__c_ulong" }, + { "__c_longlong" }, + { "__c_ulonglong" }, { "__c_long_double" }, { "cpp_type_info_ptr", "__cpp_type_info_ptr" }, { "_assert", "assert" }, diff --git a/dmd/id.h b/dmd/id.h index 81d30105eb5..39ac12a3e70 100644 --- a/dmd/id.h +++ b/dmd/id.h @@ -31,6 +31,8 @@ struct Id static Identifier *offsetof; static Identifier *__c_long; static Identifier *__c_ulong; + static Identifier *__c_longlong; + static Identifier *__c_ulonglong; static Identifier *__c_long_double; static Identifier *__switch; static Identifier *crt_constructor; diff --git a/gen/abi.cpp b/gen/abi.cpp index c7735746047..62855c00dad 100644 --- a/gen/abi.cpp +++ b/gen/abi.cpp @@ -197,6 +197,7 @@ bool TargetABI::isMagicCppStruct(Type *t) { Identifier *id = static_cast(t)->sym->ident; return (id == Id::__c_long) || (id == Id::__c_ulong) || + (id == Id::__c_longlong) || (id == Id::__c_ulonglong) || (id == Id::__c_long_double); } diff --git a/gen/abi.h b/gen/abi.h index 89ad1175c8b..5fa553d4290 100644 --- a/gen/abi.h +++ b/gen/abi.h @@ -181,8 +181,8 @@ struct TargetABI { /// * complex number static bool isAggregate(Type *t); - /// The frontend uses magic structs to express the variable-sized C types - /// ((unsigned) long, long double) for C++ mangling purposes. + /// The frontend uses magic structs to express some primitive C types + /// ((unsigned) long (long), long double) for C++ mangling purposes. static bool isMagicCppStruct(Type *t); /// Returns true if the D type is a Plain-Old-Datatype, optionally excluding From b70a90807e4c4ec17b498cd3097c4ed9d02b8d43 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 9 Apr 2018 21:53:22 +0200 Subject: [PATCH 5/9] druntime: Add aliases c(pp)_(u)longlong and c(pp)_(u)int64_t --- runtime/druntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/druntime b/runtime/druntime index 3cca35e7457..b12b0142f31 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 3cca35e7457643e88ae285cfd9150a5634c5f50b +Subproject commit b12b0142f312d81771395024daf87c2f11becaa6 From 3103b620b53494fc459851e7f187234ec6708e8c Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 9 Apr 2018 22:22:37 +0200 Subject: [PATCH 6/9] dmd-testsuite: Adapt & extend runnable/externmangle.d --- tests/d2/dmd-testsuite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite index 025581a647d..9d69507d04a 160000 --- a/tests/d2/dmd-testsuite +++ b/tests/d2/dmd-testsuite @@ -1 +1 @@ -Subproject commit 025581a647d36a3ff9edc7178d04f5f125995948 +Subproject commit 9d69507d04a0d1192cf5709df3efad30fac9be52 From bb6e13811eadbf55fe556bc49dbe3cb2ab0ab946 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 10 Apr 2018 00:04:30 +0200 Subject: [PATCH 7/9] dmd-testsuite: Adapt runnable/extra-files/cppb.cpp to reverted OSX mangling --- tests/d2/dmd-testsuite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite index 9d69507d04a..187c6313531 160000 --- a/tests/d2/dmd-testsuite +++ b/tests/d2/dmd-testsuite @@ -1 +1 @@ -Subproject commit 9d69507d04a0d1192cf5709df3efad30fac9be52 +Subproject commit 187c631353192339e5dabf44655c303bb6b22af7 From 7f6b7b9f1360f036cf937a69adbc65f47b4015c7 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 10 Apr 2018 00:15:43 +0200 Subject: [PATCH 8/9] Fix C long size for 64-bit MSVC target --- gen/target.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gen/target.cpp b/gen/target.cpp index 0a9546c917e..c1b5091d16f 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -39,7 +39,8 @@ void Target::_init() { cppExceptions = true; - c_longsize = global.params.is64bit ? 8 : 4; + c_longsize = + global.params.is64bit && !triple.isWindowsMSVCEnvironment() ? 8 : 4; c_long_doublesize = realsize; classinfosize = 0; // unused maxStaticDataSize = std::numeric_limits::max(); From 5ac6c85655835a227acc8678f029041d0e5b0c45 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 11 Apr 2018 01:02:18 +0200 Subject: [PATCH 9/9] Predefine version D_ObjectiveC _before_ printing predefs with -v This fixes 64bit-macOS-exclusive runnable/test18335.sh. --- dmd/mars.d | 12 +++++++++--- dmd/mars.h | 1 - driver/main.cpp | 1 - 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/dmd/mars.d b/dmd/mars.d index 9166b94d9c3..2dc4306e667 100644 --- a/dmd/mars.d +++ b/dmd/mars.d @@ -551,7 +551,14 @@ extern (C++) int mars_mainBody(ref Strings files, ref Strings libmodules) Objc._init(); builtin_init(); - version (IN_LLVM) {} else + version (IN_LLVM) + { + // LDC prints binary/version/config before entering this function. + // DMD prints the predefined versions as part of addDefaultVersionIdentifiers(). + // Let's do it here after initialization, as e.g. Objc.init() may add `D_ObjectiveC`. + printPredefinedVersions(); + } + else { printPredefinedVersions(); @@ -1610,8 +1617,7 @@ void addDefaultVersionIdentifiers() } // !IN_LLVM -// IN_LLVM replaced: `private` by `extern (C++)` -extern (C++) void printPredefinedVersions() +private void printPredefinedVersions() { if (global.params.verbose && global.versionids) { diff --git a/dmd/mars.h b/dmd/mars.h index 31fee5e86e9..b775a7ce1ca 100644 --- a/dmd/mars.h +++ b/dmd/mars.h @@ -102,7 +102,6 @@ void ensurePathToNameExists(Loc loc, const char *name); #if IN_LLVM int mars_mainBody(Strings &files, Strings &libmodules); -void printPredefinedVersions(); #endif const char *importHint(const char *s); diff --git a/driver/main.cpp b/driver/main.cpp index 2a9f0b74b65..10fa5fbcc65 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -1123,7 +1123,6 @@ int cppmain(int argc, char **argv) { void addDefaultVersionIdentifiers() { registerPredefinedVersions(); - printPredefinedVersions(); } void codegenModules(Modules &modules) {