diff --git a/dmd/target.d b/dmd/target.d index b2fbbb445e..6329f40470 100644 --- a/dmd/target.d +++ b/dmd/target.d @@ -103,30 +103,22 @@ version (IN_LLVM) // implemented in gen/target.cpp: void _init(ref const Param params); + // unused: void deinitialize(); uint alignsize(Type type); uint fieldalign(Type type); - uint critsecsize(); + + uint critsecsize() + { + if (criticalSectionSize == 0) + { + import dmd.errors; + error(Loc.initial, "Unknown critical section size"); + fatal(); + } + return criticalSectionSize; + } + Type va_listType(); - int isVectorTypeSupported(int sz, Type type); - bool isVectorOpSupported(Type type, TOK op, Type t2 = null); - - const(char)* toCppMangle(Dsymbol s) - { - if (isTargetWindowsMSVC()) - return toCppMangleMSVC(s); - else - return toCppMangleItanium(s); - } - - const(char)* cppTypeInfoMangle(ClassDeclaration cd) - { - if (isTargetWindowsMSVC()) - return cppTypeInfoMangleMSVC(cd); - else - return cppTypeInfoMangleItanium(cd); - } - - const(char)* cppTypeMangle(Type t); } else // !IN_LLVM { @@ -362,6 +354,7 @@ else // !IN_LLVM assert(0); } } +} // !IN_LLVM /** * Checks whether the target supports a vector type. @@ -376,7 +369,8 @@ else // !IN_LLVM */ extern (C++) int isVectorTypeSupported(int sz, Type type) { - if (!global.params.is64bit && !global.params.isOSX) + // LDC_FIXME: Is it possible to query the LLVM target about supported vectors? + if (!IN_LLVM && !global.params.is64bit && !global.params.isOSX) return 1; // not supported switch (type.ty) { @@ -395,7 +389,7 @@ else // !IN_LLVM default: return 2; // wrong base type } - if (sz != 16 && !(global.params.cpu >= CPU.avx && sz == 32)) + if (!IN_LLVM && sz != 16 && !(global.params.cpu >= CPU.avx && sz == 32)) return 3; // wrong size return 0; } @@ -409,7 +403,7 @@ else // !IN_LLVM * Returns: * true if the operation is supported or type is not a vector */ - extern (C++) bool isVectorOpSupported(Type type, ubyte op, Type t2 = null) + extern (C++) bool isVectorOpSupported(Type type, TOK op, Type t2 = null) { import dmd.tokens; @@ -417,6 +411,11 @@ else // !IN_LLVM return true; // not a vector op auto tvec = cast(TypeVector) type; + // LDC_FIXME: + // Most of the binops only work with `t2` being the same IR type as `tvec` + // (LLVM restriction). We'd need to be more strict here and/or convert + // the rhs to a matching type during codegen (e.g., promote scalars to + // vectors). bool supported; switch (op) { @@ -424,12 +423,24 @@ else // !IN_LLVM supported = tvec.isscalar(); break; +version (IN_LLVM) +{ + case TOK.lessThan, TOK.greaterThan, TOK.lessOrEqual, TOK.greaterOrEqual: + supported = false; + break; + case TOK.equal, TOK.notEqual, TOK.identity, TOK.notIdentity: + supported = true; + break; +} +else +{ case TOK.lessThan, TOK.greaterThan, TOK.lessOrEqual, TOK.greaterOrEqual, TOK.equal, TOK.notEqual, TOK.identity, TOK.notIdentity: supported = false; break; +} case TOK.leftShift, TOK.leftShiftAssign, TOK.rightShift, TOK.rightShiftAssign, TOK.unsignedRightShift, TOK.unsignedRightShiftAssign: - supported = false; + supported = IN_LLVM && tvec.isintegral(); break; case TOK.add, TOK.addAssign, TOK.min, TOK.minAssign: @@ -437,6 +448,12 @@ else // !IN_LLVM break; case TOK.mul, TOK.mulAssign: +version (IN_LLVM) +{ + supported = tvec.isscalar(); +} +else +{ // only floats and short[8]/ushort[8] (PMULLW) if (tvec.isfloating() || tvec.elementType().size(Loc.initial) == 2 || // int[4]/uint[4] with SSE4.1 (PMULLD) @@ -444,14 +461,15 @@ else // !IN_LLVM supported = true; else supported = false; +} break; case TOK.div, TOK.divAssign: - supported = tvec.isfloating(); + supported = IN_LLVM ? tvec.isscalar() : tvec.isfloating(); break; case TOK.mod, TOK.modAssign: - supported = false; + supported = IN_LLVM && tvec.isscalar(); break; case TOK.and, TOK.andAssign, TOK.or, TOK.orAssign, TOK.xor, TOK.xorAssign: @@ -487,12 +505,22 @@ else // !IN_LLVM */ extern (C++) const(char)* toCppMangle(Dsymbol s) { +version (IN_LLVM) +{ + if (isTargetWindowsMSVC()) + return toCppMangleMSVC(s); + else + return toCppMangleItanium(s); +} +else +{ static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.DragonFlyBSD || TARGET.Solaris) return toCppMangleItanium(s); else static if (TARGET.Windows) return toCppMangleMSVC(s); else static assert(0, "fix this"); +} } /** @@ -504,12 +532,22 @@ else // !IN_LLVM */ extern (C++) const(char)* cppTypeInfoMangle(ClassDeclaration cd) { +version (IN_LLVM) +{ + if (isTargetWindowsMSVC()) + return cppTypeInfoMangleMSVC(cd); + else + return cppTypeInfoMangleItanium(cd); +} +else +{ static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) return cppTypeInfoMangleItanium(cd); else static if (TARGET.Windows) return cppTypeInfoMangleMSVC(cd); else static assert(0, "fix this"); +} } /** @@ -520,11 +558,17 @@ else // !IN_LLVM * string if type is mangled specially on target * null if unhandled */ +version (IN_LLVM) +{ + extern (C++) const(char)* cppTypeMangle(Type t); +} +else +{ extern (C++) const(char)* cppTypeMangle(Type t) { return null; } -} // !IN_LLVM +} /** * Get the type that will really be used for passing the given argument diff --git a/gen/binops.cpp b/gen/binops.cpp index 301951fee0..979a53bdd4 100644 --- a/gen/binops.cpp +++ b/gen/binops.cpp @@ -384,7 +384,7 @@ LLValue *DtoBinFloatsEquals(Loc &loc, DValue *lhs, DValue *rhs, TOK op) { LLValue *mergeVectorEquals(LLValue *resultsVector, TOK op) { // `resultsVector` is a vector of i1 values, the pair-wise results. - // Bitcast to an integer and checks the bits via additional integer + // Bitcast to an integer and check the bits via additional integer // comparison. const auto sizeInBits = getTypeBitSize(resultsVector->getType()); LLType *integerType = LLType::getIntNTy(gIR->context(), sizeInBits); diff --git a/gen/target.cpp b/gen/target.cpp index 5e16dc5802..0828c8197e 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -31,6 +31,63 @@ TypeTuple *toArgTypes(Type *t); // in dmd/argtypes_sysv_x64.d: TypeTuple *toArgTypes_sysv_x64(Type *t); +namespace { +/****************************** + * Return size of alias Mutex in druntime/src/rt/monitor_.d, or, more precisely, + * the size of the native critical section as 2nd field in struct + * D_CRITICAL_SECTION (after a pointer). D_CRITICAL_SECTION is pointer-size + * aligned, so the returned field size is a multiple of pointer-size. + */ +unsigned getCriticalSectionSize(const Param ¶ms) { + const bool is64bit = params.is64bit; + + // Windows: sizeof(CRITICAL_SECTION) + if (params.isWindows) + return is64bit ? 40 : 24; + + // POSIX: sizeof(pthread_mutex_t) + // based on druntime/src/core/sys/posix/sys/types.d + const auto &triple = *params.targetTriple; + const auto arch = triple.getArch(); + switch (triple.getOS()) { + case llvm::Triple::Linux: + if (triple.getEnvironment() == llvm::Triple::Android) { + // 32-bit integer rounded up to pointer size + return gDataLayout->getPointerSize(); + } + if (arch == llvm::Triple::aarch64 || arch == llvm::Triple::aarch64_be) + return 48; + return is64bit ? 40 : 24; + + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + return is64bit ? 64 : 44; + + case llvm::Triple::NetBSD: + return is64bit ? 48 : 28; + + case llvm::Triple::FreeBSD: + case llvm::Triple::OpenBSD: + case llvm::Triple::DragonFly: + return gDataLayout->getPointerSize(); + + case llvm::Triple::Solaris: + return 24; + + default: + break; + } + +#ifndef _MSC_VER + unsigned hostSize = sizeof(pthread_mutex_t); + warning(Loc(), "Assuming critical section size = %u bytes", hostSize); + return hostSize; +#else + return 0; +#endif +} +} // anonymous namespace + void Target::_init(const Param ¶ms) { CTFloat::initialize(); @@ -39,26 +96,23 @@ void Target::_init(const Param ¶ms) { RealProperties._init(); const auto &triple = *params.targetTriple; + const bool isMSVC = triple.isWindowsMSVCEnvironment(); + llvm::Type *const real = DtoType(Type::basic[Tfloat80]); ptrsize = gDataLayout->getPointerSize(); - - llvm::Type *const real = DtoType(Type::basic[Tfloat80]); realsize = gDataLayout->getTypeAllocSize(real); realpad = realsize - gDataLayout->getTypeStoreSize(real); realalignsize = gDataLayout->getABITypeAlignment(real); - - // according to DMD, only for MSVC++: - reverseCppOverloads = triple.isWindowsMSVCEnvironment(); - - cppExceptions = true; - - c_longsize = - global.params.is64bit && !triple.isWindowsMSVCEnvironment() ? 8 : 4; - c_long_doublesize = realsize; classinfosize = 0; // unused maxStaticDataSize = std::numeric_limits::max(); - twoDtorInVtable = !triple.isWindowsMSVCEnvironment(); + c_longsize = global.params.is64bit && !isMSVC ? 8 : 4; + c_long_doublesize = realsize; + criticalSectionSize = getCriticalSectionSize(params); + + reverseCppOverloads = isMSVC; // according to DMD, only for MSVC++ + cppExceptions = true; + twoDtorInVtable = !isMSVC; // Finalize RealProperties for the target's `real` type. @@ -134,83 +188,8 @@ unsigned Target::alignsize(Type *type) { */ unsigned Target::fieldalign(Type *type) { return DtoAlignment(type); } -/****************************** - * Return size of alias Mutex in druntime/src/rt/monitor_.d, or, more precisely, - * the size of the native critical section as 2nd field in struct - * D_CRITICAL_SECTION (after a pointer). D_CRITICAL_SECTION is pointer-size - * aligned, so the returned field size is a multiple of pointer-size. - */ -unsigned Target::critsecsize() { - const bool is64bit = global.params.is64bit; - - // Windows: sizeof(CRITICAL_SECTION) - if (global.params.isWindows) - return is64bit ? 40 : 24; - - // POSIX: sizeof(pthread_mutex_t) - // based on druntime/src/core/sys/posix/sys/types.d - const auto &triple = *global.params.targetTriple; - const auto arch = triple.getArch(); - switch (triple.getOS()) { - case llvm::Triple::Linux: - if (triple.getEnvironment() == llvm::Triple::Android) - return ptrsize; // 32-bit integer rounded up to pointer size - if (arch == llvm::Triple::aarch64 || arch == llvm::Triple::aarch64_be) - return 48; - return is64bit ? 40 : 24; - - case llvm::Triple::MacOSX: - return is64bit ? 64 : 44; - - case llvm::Triple::NetBSD: - return is64bit ? 48 : 28; - - case llvm::Triple::FreeBSD: - case llvm::Triple::OpenBSD: - case llvm::Triple::DragonFly: - return ptrsize; - - case llvm::Triple::Solaris: - return 24; - - default: - break; - } - -#ifndef _MSC_VER - unsigned hostSize = sizeof(pthread_mutex_t); - warning(Loc(), "Assuming critical section size = %u bytes", hostSize); - return hostSize; -#else - error(Loc(), "Unknown critical section size"); - fatal(); - return 0; -#endif -} - Type *Target::va_listType() { return gABI->vaListType(); } -/****************************** - * Check if the given type is supported for this target - * 0: supported - * 1: not supported - * 2: wrong size - * 3: wrong base type - */ -int Target::isVectorTypeSupported(int sz, Type *type) { - // FIXME: Is it possible to query the LLVM target about supported vectors? - return 0; -} - -/****************************** - * Checks whether the target supports operation `op` for vectors of type `type`. - * For binary ops `t2` is the type of the 2nd operand. - */ -bool Target::isVectorOpSupported(Type *type, TOK op, Type *t2) { - // FIXME - return true; -} - /** * Gets vendor-specific type mangling for C++ ABI. * Params: diff --git a/gen/toir.cpp b/gen/toir.cpp index 033b56170d..a93a2017ad 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1974,6 +1974,10 @@ public: assert(lv->getType() == rv->getType()); eval = (e->op == TOKidentity) ? p->ir->CreateICmpEQ(lv, rv) : p->ir->CreateICmpNE(lv, rv); + if (t1->ty == Tvector) { + eval = mergeVectorEquals(eval, + e->op == TOKidentity ? TOKequal : TOKnotequal); + } } result = new DImValue(e->type, eval); } diff --git a/tests/codegen/vector_ops.d b/tests/codegen/vector_ops.d new file mode 100644 index 0000000000..a469551ac4 --- /dev/null +++ b/tests/codegen/vector_ops.d @@ -0,0 +1,45 @@ +// REQUIRES: atleast_llvm500 +// RUN: %ldc -run %s + +import core.simd; + +void main() +{ + static void testGenericOps(T)() + { + const T v = [ 1, -2, 3, -4 ]; + + assert(-v == [ -1, 2, -3, 4 ]); + assert(+v == v); + + T v2 = v; + assert(v2 == v && !(v2 != v)); + assert(v2 is v && !(v2 !is v)); + v2[0] = 0; + assert(v2 != v && !(v2 == v)); + assert(v2 !is v && !(v2 is v)); + + assert(v + v == [ 2, -4, 6, -8 ]); + assert(v - v == T(0)); + assert(v * v == [ 1, 4, 9, 16 ]); + assert(v / v == T(1)); + assert(v % T(3) == [ 1, -2, 0, -1 ]); + } + + testGenericOps!float4(); + testGenericOps!int4(); + + const float4 nan = float.nan; + assert(nan != nan && !(nan == nan)); + assert(nan is nan && !(nan !is nan)); + + const int4 i = [ 1, 2, 3, 4 ]; + assert(i << i == [ 2, 8, 24, 64 ]); + + const int4 a = [ 0b1, 0b10, 0b101, 0b100011 ]; + const int4 b = 0b110; + assert((a & b) == [ 0, 0b10, 0b100, 0b10 ]); + assert((a | b) == [ 0b111, 0b110, 0b111, 0b100111 ]); + assert((a ^ b) == [ 0b111, 0b100, 0b11, 0b100101 ]); + assert(~a == [ ~0b1, ~0b10, ~0b101, ~0b100011 ]); +} diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite index 4db6a6265a..bc1f35b522 160000 --- a/tests/d2/dmd-testsuite +++ b/tests/d2/dmd-testsuite @@ -1 +1 @@ -Subproject commit 4db6a6265a36ba49dd06a3fe2f272b634b6cec6e +Subproject commit bc1f35b522f5194d8b3b5afb462cc528a324fd17