Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Fix Issue 19204 - hashOf doesn't accept SIMD vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
n8sh committed Oct 24, 2018
1 parent 8074173 commit 9b293c9
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 5 deletions.
24 changes: 23 additions & 1 deletion src/core/internal/convert.d
Expand Up @@ -595,7 +595,7 @@ const(ubyte)[] toUbyte(T)(const T[] arr) if ((is(typeof(toUbyte(arr[0])) == cons
}

@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T == enum))
const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T == enum) && !is(T == __vector))
{
static if (T.sizeof == 1)
{
Expand Down Expand Up @@ -630,6 +630,28 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T
}
}

@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == __vector))
{
if (!__ctfe)
return (cast(const ubyte*) &val)[0 .. T.sizeof];
else static if (is(typeof(val[0]) : void))
assert(0, "Unable to compute byte representation of " ~ T.stringof ~ " at compile time.");
else
{
// This code looks like it should work in CTFE but it segfaults:
// auto a = val.array;
// return toUbyte(a);
alias E = typeof(val[0]);
ubyte[] result = ctfe_alloc(T.sizeof);
for (size_t i = 0, j = 0; i < T.sizeof; i += E.sizeof, ++j)
{
result[i .. i + E.sizeof] = toUbyte(val[j]);
}
return result;
}
}

@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T == cdouble) ||is(Unqual!T == creal))
{
Expand Down
30 changes: 26 additions & 4 deletions src/core/internal/hash.d
Expand Up @@ -129,7 +129,7 @@ private template canBitwiseHash(T)
}
}

private template UnqualUnsigned(T) if (__traits(isIntegral, T))
private template UnqualUnsigned(T) if (__traits(isIntegral, T) && !is(T == __vector))
{
static if (T.sizeof == ubyte.sizeof) alias UnqualUnsigned = ubyte;
else static if (T.sizeof == ushort.sizeof) alias UnqualUnsigned = ushort;
Expand Down Expand Up @@ -342,15 +342,15 @@ if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStati
//arithmetic type hash
@trusted @nogc nothrow pure
size_t hashOf(T)(scope const T val) if (!is(T == enum) && __traits(isArithmetic, T)
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof)
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof && !is(T == __vector))
{
return cast(UnqualUnsigned!T) val;
}

//arithmetic type hash
@trusted @nogc nothrow pure
size_t hashOf(T)(scope const T val, size_t seed) if (!is(T == enum) && __traits(isArithmetic, T)
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof)
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof && !is(T == __vector))
{
static if (size_t.sizeof < ulong.sizeof)
{
Expand Down Expand Up @@ -381,7 +381,7 @@ size_t hashOf(T)(scope const T val, size_t seed) if (!is(T == enum) && __traits(
//arithmetic type hash
@trusted @nogc nothrow pure
size_t hashOf(T)(scope const T val, size_t seed = 0) if (!is(T == enum) && __traits(isArithmetic, T)
&& (!__traits(isIntegral, T) || T.sizeof > size_t.sizeof))
&& (!__traits(isIntegral, T) || T.sizeof > size_t.sizeof) && !is(T == __vector))
{
static if (__traits(isFloating, val))
{
Expand Down Expand Up @@ -423,6 +423,28 @@ size_t hashOf(T)(scope const T val, size_t seed = 0) if (!is(T == enum) && __tra
}
}

size_t hashOf(T)(scope const auto ref T val, size_t seed = 0) @safe @nogc nothrow pure
if (is(T == __vector) && !is(T == enum))
{
static if (__traits(isFloating, T) && (floatCoalesceZeroes || floatCoalesceNaNs))
{
if (__ctfe)
{
// Workaround for CTFE bug.
alias E = Unqual!(typeof(val[0]));
E[T.sizeof / E.sizeof] array;
foreach (i; 0 .. T.sizeof / E.sizeof)
array[i] = val[i];
return hashOf(array, seed);
}
return hashOf(val.array, seed);
}
else
{
return bytesHashAlignedBy!T(toUbyte(val), seed);
}
}

//typeof(null) hash. CTFE supported
@trusted @nogc nothrow pure
size_t hashOf(T)(scope const T val) if (!is(T == enum) && is(T : typeof(null)))
Expand Down
30 changes: 30 additions & 0 deletions test/hash/src/test_hash.d
Expand Up @@ -6,6 +6,7 @@ void main()
issue18918();
issue18925();
issue19005();
issue19204();
issue19262();
issue19282();
testTypeInfoArrayGetHash1();
Expand Down Expand Up @@ -87,6 +88,35 @@ void issue19005() @nogc nothrow pure @safe
auto hash = date.hashOf;
}

/// Accept SIMD vectors.
void issue19204() @nogc nothrow pure @safe
{
version (D_SIMD)
{
static import simd = core.simd;
static if (is(simd.int4)) // __traits(isArithmetic)
{{
enum simd.int4 val = [1,2,3,4];
enum ctfeHash = hashOf(val);
simd.int4 rtVal = val;
auto rtHash = hashOf(rtVal);
assert(ctfeHash == rtHash);
}}
static if (is(simd.void16)) // non __traits(isArithmetic)
{{
auto h = hashOf(simd.void16.init);
}}
static if (is(simd.float4)) // __traits(isArithmetic) and __traits(isFloating)
{{
enum simd.float4 val = [1.1f, 2.2f, 3.3f, 4.4f];
enum ctfeHash = hashOf(val);
simd.float4 rtVal = val;
auto rtHash = hashOf(rtVal);
assert(ctfeHash == rtHash);
}}
}
}

/// hashOf associative array should infer nothrow
void issue19262() nothrow
{
Expand Down

0 comments on commit 9b293c9

Please sign in to comment.