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

Commit 9b293c9

Browse files
committed
Fix Issue 19204 - hashOf doesn't accept SIMD vectors
1 parent 8074173 commit 9b293c9

File tree

3 files changed

+79
-5
lines changed

3 files changed

+79
-5
lines changed

src/core/internal/convert.d

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ const(ubyte)[] toUbyte(T)(const T[] arr) if ((is(typeof(toUbyte(arr[0])) == cons
595595
}
596596

597597
@trusted pure nothrow @nogc
598-
const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T == enum))
598+
const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T == enum) && !is(T == __vector))
599599
{
600600
static if (T.sizeof == 1)
601601
{
@@ -630,6 +630,28 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T
630630
}
631631
}
632632

633+
@trusted pure nothrow @nogc
634+
const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == __vector))
635+
{
636+
if (!__ctfe)
637+
return (cast(const ubyte*) &val)[0 .. T.sizeof];
638+
else static if (is(typeof(val[0]) : void))
639+
assert(0, "Unable to compute byte representation of " ~ T.stringof ~ " at compile time.");
640+
else
641+
{
642+
// This code looks like it should work in CTFE but it segfaults:
643+
// auto a = val.array;
644+
// return toUbyte(a);
645+
alias E = typeof(val[0]);
646+
ubyte[] result = ctfe_alloc(T.sizeof);
647+
for (size_t i = 0, j = 0; i < T.sizeof; i += E.sizeof, ++j)
648+
{
649+
result[i .. i + E.sizeof] = toUbyte(val[j]);
650+
}
651+
return result;
652+
}
653+
}
654+
633655
@trusted pure nothrow @nogc
634656
const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T == cdouble) ||is(Unqual!T == creal))
635657
{

src/core/internal/hash.d

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ private template canBitwiseHash(T)
129129
}
130130
}
131131

132-
private template UnqualUnsigned(T) if (__traits(isIntegral, T))
132+
private template UnqualUnsigned(T) if (__traits(isIntegral, T) && !is(T == __vector))
133133
{
134134
static if (T.sizeof == ubyte.sizeof) alias UnqualUnsigned = ubyte;
135135
else static if (T.sizeof == ushort.sizeof) alias UnqualUnsigned = ushort;
@@ -342,15 +342,15 @@ if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStati
342342
//arithmetic type hash
343343
@trusted @nogc nothrow pure
344344
size_t hashOf(T)(scope const T val) if (!is(T == enum) && __traits(isArithmetic, T)
345-
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof)
345+
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof && !is(T == __vector))
346346
{
347347
return cast(UnqualUnsigned!T) val;
348348
}
349349

350350
//arithmetic type hash
351351
@trusted @nogc nothrow pure
352352
size_t hashOf(T)(scope const T val, size_t seed) if (!is(T == enum) && __traits(isArithmetic, T)
353-
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof)
353+
&& __traits(isIntegral, T) && T.sizeof <= size_t.sizeof && !is(T == __vector))
354354
{
355355
static if (size_t.sizeof < ulong.sizeof)
356356
{
@@ -381,7 +381,7 @@ size_t hashOf(T)(scope const T val, size_t seed) if (!is(T == enum) && __traits(
381381
//arithmetic type hash
382382
@trusted @nogc nothrow pure
383383
size_t hashOf(T)(scope const T val, size_t seed = 0) if (!is(T == enum) && __traits(isArithmetic, T)
384-
&& (!__traits(isIntegral, T) || T.sizeof > size_t.sizeof))
384+
&& (!__traits(isIntegral, T) || T.sizeof > size_t.sizeof) && !is(T == __vector))
385385
{
386386
static if (__traits(isFloating, val))
387387
{
@@ -423,6 +423,28 @@ size_t hashOf(T)(scope const T val, size_t seed = 0) if (!is(T == enum) && __tra
423423
}
424424
}
425425

426+
size_t hashOf(T)(scope const auto ref T val, size_t seed = 0) @safe @nogc nothrow pure
427+
if (is(T == __vector) && !is(T == enum))
428+
{
429+
static if (__traits(isFloating, T) && (floatCoalesceZeroes || floatCoalesceNaNs))
430+
{
431+
if (__ctfe)
432+
{
433+
// Workaround for CTFE bug.
434+
alias E = Unqual!(typeof(val[0]));
435+
E[T.sizeof / E.sizeof] array;
436+
foreach (i; 0 .. T.sizeof / E.sizeof)
437+
array[i] = val[i];
438+
return hashOf(array, seed);
439+
}
440+
return hashOf(val.array, seed);
441+
}
442+
else
443+
{
444+
return bytesHashAlignedBy!T(toUbyte(val), seed);
445+
}
446+
}
447+
426448
//typeof(null) hash. CTFE supported
427449
@trusted @nogc nothrow pure
428450
size_t hashOf(T)(scope const T val) if (!is(T == enum) && is(T : typeof(null)))

test/hash/src/test_hash.d

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ void main()
66
issue18918();
77
issue18925();
88
issue19005();
9+
issue19204();
910
issue19262();
1011
issue19282();
1112
testTypeInfoArrayGetHash1();
@@ -87,6 +88,35 @@ void issue19005() @nogc nothrow pure @safe
8788
auto hash = date.hashOf;
8889
}
8990

91+
/// Accept SIMD vectors.
92+
void issue19204() @nogc nothrow pure @safe
93+
{
94+
version (D_SIMD)
95+
{
96+
static import simd = core.simd;
97+
static if (is(simd.int4)) // __traits(isArithmetic)
98+
{{
99+
enum simd.int4 val = [1,2,3,4];
100+
enum ctfeHash = hashOf(val);
101+
simd.int4 rtVal = val;
102+
auto rtHash = hashOf(rtVal);
103+
assert(ctfeHash == rtHash);
104+
}}
105+
static if (is(simd.void16)) // non __traits(isArithmetic)
106+
{{
107+
auto h = hashOf(simd.void16.init);
108+
}}
109+
static if (is(simd.float4)) // __traits(isArithmetic) and __traits(isFloating)
110+
{{
111+
enum simd.float4 val = [1.1f, 2.2f, 3.3f, 4.4f];
112+
enum ctfeHash = hashOf(val);
113+
simd.float4 rtVal = val;
114+
auto rtHash = hashOf(rtVal);
115+
assert(ctfeHash == rtHash);
116+
}}
117+
}
118+
}
119+
90120
/// hashOf associative array should infer nothrow
91121
void issue19262() nothrow
92122
{

0 commit comments

Comments
 (0)