mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-05 09:31:03 +03:00
Disallow some vector ops and fix integral vector identity comparisons
Bail out on unsupported vector ops (not checking the rhs type for binops though) in the frontend instead of causing LLVM errors. Also precompute the target's critical section size once at startup, like DMD.
This commit is contained in:
parent
8dd4f5f893
commit
a44c78fb88
6 changed files with 189 additions and 117 deletions
100
dmd/target.d
100
dmd/target.d
|
@ -103,30 +103,22 @@ version (IN_LLVM)
|
||||||
|
|
||||||
// implemented in gen/target.cpp:
|
// implemented in gen/target.cpp:
|
||||||
void _init(ref const Param params);
|
void _init(ref const Param params);
|
||||||
|
// unused: void deinitialize();
|
||||||
uint alignsize(Type type);
|
uint alignsize(Type type);
|
||||||
uint fieldalign(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();
|
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
|
else // !IN_LLVM
|
||||||
{
|
{
|
||||||
|
@ -362,6 +354,7 @@ else // !IN_LLVM
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // !IN_LLVM
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the target supports a vector type.
|
* Checks whether the target supports a vector type.
|
||||||
|
@ -376,7 +369,8 @@ else // !IN_LLVM
|
||||||
*/
|
*/
|
||||||
extern (C++) int isVectorTypeSupported(int sz, Type type)
|
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
|
return 1; // not supported
|
||||||
switch (type.ty)
|
switch (type.ty)
|
||||||
{
|
{
|
||||||
|
@ -395,7 +389,7 @@ else // !IN_LLVM
|
||||||
default:
|
default:
|
||||||
return 2; // wrong base type
|
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 3; // wrong size
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -409,7 +403,7 @@ else // !IN_LLVM
|
||||||
* Returns:
|
* Returns:
|
||||||
* true if the operation is supported or type is not a vector
|
* 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;
|
import dmd.tokens;
|
||||||
|
|
||||||
|
@ -417,6 +411,11 @@ else // !IN_LLVM
|
||||||
return true; // not a vector op
|
return true; // not a vector op
|
||||||
auto tvec = cast(TypeVector) type;
|
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;
|
bool supported;
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
|
@ -424,12 +423,24 @@ else // !IN_LLVM
|
||||||
supported = tvec.isscalar();
|
supported = tvec.isscalar();
|
||||||
break;
|
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:
|
case TOK.lessThan, TOK.greaterThan, TOK.lessOrEqual, TOK.greaterOrEqual, TOK.equal, TOK.notEqual, TOK.identity, TOK.notIdentity:
|
||||||
supported = false;
|
supported = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case TOK.leftShift, TOK.leftShiftAssign, TOK.rightShift, TOK.rightShiftAssign, TOK.unsignedRightShift, TOK.unsignedRightShiftAssign:
|
case TOK.leftShift, TOK.leftShiftAssign, TOK.rightShift, TOK.rightShiftAssign, TOK.unsignedRightShift, TOK.unsignedRightShiftAssign:
|
||||||
supported = false;
|
supported = IN_LLVM && tvec.isintegral();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK.add, TOK.addAssign, TOK.min, TOK.minAssign:
|
case TOK.add, TOK.addAssign, TOK.min, TOK.minAssign:
|
||||||
|
@ -437,6 +448,12 @@ else // !IN_LLVM
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK.mul, TOK.mulAssign:
|
case TOK.mul, TOK.mulAssign:
|
||||||
|
version (IN_LLVM)
|
||||||
|
{
|
||||||
|
supported = tvec.isscalar();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// only floats and short[8]/ushort[8] (PMULLW)
|
// only floats and short[8]/ushort[8] (PMULLW)
|
||||||
if (tvec.isfloating() || tvec.elementType().size(Loc.initial) == 2 ||
|
if (tvec.isfloating() || tvec.elementType().size(Loc.initial) == 2 ||
|
||||||
// int[4]/uint[4] with SSE4.1 (PMULLD)
|
// int[4]/uint[4] with SSE4.1 (PMULLD)
|
||||||
|
@ -444,14 +461,15 @@ else // !IN_LLVM
|
||||||
supported = true;
|
supported = true;
|
||||||
else
|
else
|
||||||
supported = false;
|
supported = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK.div, TOK.divAssign:
|
case TOK.div, TOK.divAssign:
|
||||||
supported = tvec.isfloating();
|
supported = IN_LLVM ? tvec.isscalar() : tvec.isfloating();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK.mod, TOK.modAssign:
|
case TOK.mod, TOK.modAssign:
|
||||||
supported = false;
|
supported = IN_LLVM && tvec.isscalar();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK.and, TOK.andAssign, TOK.or, TOK.orAssign, TOK.xor, TOK.xorAssign:
|
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)
|
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)
|
static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.DragonFlyBSD || TARGET.Solaris)
|
||||||
return toCppMangleItanium(s);
|
return toCppMangleItanium(s);
|
||||||
else static if (TARGET.Windows)
|
else static if (TARGET.Windows)
|
||||||
return toCppMangleMSVC(s);
|
return toCppMangleMSVC(s);
|
||||||
else
|
else
|
||||||
static assert(0, "fix this");
|
static assert(0, "fix this");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -504,12 +532,22 @@ else // !IN_LLVM
|
||||||
*/
|
*/
|
||||||
extern (C++) const(char)* cppTypeInfoMangle(ClassDeclaration cd)
|
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)
|
static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD)
|
||||||
return cppTypeInfoMangleItanium(cd);
|
return cppTypeInfoMangleItanium(cd);
|
||||||
else static if (TARGET.Windows)
|
else static if (TARGET.Windows)
|
||||||
return cppTypeInfoMangleMSVC(cd);
|
return cppTypeInfoMangleMSVC(cd);
|
||||||
else
|
else
|
||||||
static assert(0, "fix this");
|
static assert(0, "fix this");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -520,11 +558,17 @@ else // !IN_LLVM
|
||||||
* string if type is mangled specially on target
|
* string if type is mangled specially on target
|
||||||
* null if unhandled
|
* null if unhandled
|
||||||
*/
|
*/
|
||||||
|
version (IN_LLVM)
|
||||||
|
{
|
||||||
|
extern (C++) const(char)* cppTypeMangle(Type t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
extern (C++) const(char)* cppTypeMangle(Type t)
|
extern (C++) const(char)* cppTypeMangle(Type t)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} // !IN_LLVM
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the type that will really be used for passing the given argument
|
* Get the type that will really be used for passing the given argument
|
||||||
|
|
|
@ -384,7 +384,7 @@ LLValue *DtoBinFloatsEquals(Loc &loc, DValue *lhs, DValue *rhs, TOK op) {
|
||||||
|
|
||||||
LLValue *mergeVectorEquals(LLValue *resultsVector, TOK op) {
|
LLValue *mergeVectorEquals(LLValue *resultsVector, TOK op) {
|
||||||
// `resultsVector` is a vector of i1 values, the pair-wise results.
|
// `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.
|
// comparison.
|
||||||
const auto sizeInBits = getTypeBitSize(resultsVector->getType());
|
const auto sizeInBits = getTypeBitSize(resultsVector->getType());
|
||||||
LLType *integerType = LLType::getIntNTy(gIR->context(), sizeInBits);
|
LLType *integerType = LLType::getIntNTy(gIR->context(), sizeInBits);
|
||||||
|
|
153
gen/target.cpp
153
gen/target.cpp
|
@ -31,6 +31,63 @@ TypeTuple *toArgTypes(Type *t);
|
||||||
// in dmd/argtypes_sysv_x64.d:
|
// in dmd/argtypes_sysv_x64.d:
|
||||||
TypeTuple *toArgTypes_sysv_x64(Type *t);
|
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) {
|
void Target::_init(const Param ¶ms) {
|
||||||
CTFloat::initialize();
|
CTFloat::initialize();
|
||||||
|
|
||||||
|
@ -39,26 +96,23 @@ void Target::_init(const Param ¶ms) {
|
||||||
RealProperties._init();
|
RealProperties._init();
|
||||||
|
|
||||||
const auto &triple = *params.targetTriple;
|
const auto &triple = *params.targetTriple;
|
||||||
|
const bool isMSVC = triple.isWindowsMSVCEnvironment();
|
||||||
|
llvm::Type *const real = DtoType(Type::basic[Tfloat80]);
|
||||||
|
|
||||||
ptrsize = gDataLayout->getPointerSize();
|
ptrsize = gDataLayout->getPointerSize();
|
||||||
|
|
||||||
llvm::Type *const real = DtoType(Type::basic[Tfloat80]);
|
|
||||||
realsize = gDataLayout->getTypeAllocSize(real);
|
realsize = gDataLayout->getTypeAllocSize(real);
|
||||||
realpad = realsize - gDataLayout->getTypeStoreSize(real);
|
realpad = realsize - gDataLayout->getTypeStoreSize(real);
|
||||||
realalignsize = gDataLayout->getABITypeAlignment(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
|
classinfosize = 0; // unused
|
||||||
maxStaticDataSize = std::numeric_limits<unsigned long long>::max();
|
maxStaticDataSize = std::numeric_limits<unsigned long long>::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.
|
// 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); }
|
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(); }
|
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.
|
* Gets vendor-specific type mangling for C++ ABI.
|
||||||
* Params:
|
* Params:
|
||||||
|
|
|
@ -1974,6 +1974,10 @@ public:
|
||||||
assert(lv->getType() == rv->getType());
|
assert(lv->getType() == rv->getType());
|
||||||
eval = (e->op == TOKidentity) ? p->ir->CreateICmpEQ(lv, rv)
|
eval = (e->op == TOKidentity) ? p->ir->CreateICmpEQ(lv, rv)
|
||||||
: p->ir->CreateICmpNE(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);
|
result = new DImValue(e->type, eval);
|
||||||
}
|
}
|
||||||
|
|
45
tests/codegen/vector_ops.d
Normal file
45
tests/codegen/vector_ops.d
Normal file
|
@ -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 ]);
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4db6a6265a36ba49dd06a3fe2f272b634b6cec6e
|
Subproject commit bc1f35b522f5194d8b3b5afb462cc528a324fd17
|
Loading…
Add table
Add a link
Reference in a new issue