Runtime: Hardware Acceleration for unsupported overloads

Created on 23 Jun 2019  路  7Comments  路  Source: dotnet/runtime

Some methods in System.Runtime.Intrinsics.X86 don't have overloads for certain data types. For example:

long u1 = 12L,
long u2 = 14L;
var vectorOne = Vector128.Create(u1);
var vectorTwo = Vector128.Create(u2);
var mask = Sse2.MoveMask(Sse2.CompareEqual(vectorOne, vectorTwo))
...

While this is expected as there is no hardware instruction for them. Is there anything I can do as a workaround to compare, in this case, two Vector128 of data type long using Sse2? Such as reinterpreting, casting, different APIs?

area-System.Runtime.Intrinsics question

All 7 comments

If you only care about equality/inequality then yes, you can reinterpret vectors to use a different integer type. Otherwise you should be able to use Subtract and then MoveMask to extract the sign bits.

Thanks, I've tried reinterpreting it as double as I thought it needs to have the same amount of 8 bytes in memory but that didn't worked in some cases. Using an integer type as you said however works fine.

I'm also checking for CompareGreaterThan and CompareLessThan. Can you show me a short code example how I can compare them then?

Thanks, I've tried reinterpreting it as double as I thought it needs to have the same amount of 8 bytes in memory but that didn't worked in some cases. Using an integer type as you said however works fine.

Yes, floating point compares cannot be used in this case because floating point has various special values (NaN, negative 0 etc.).

I'm also checking for CompareGreaterThan and CompareLessThan. Can you show me a short code example how I can compare them then?

If you're not concerned about integer overflow then LessThan is pretty simple: x < y iff x - y < 0 and x - y < 0 iff signbit(x - y) = 1. To get the sign bits:
C# Sse2.MoveMask(Sse2.Subtract(v1, v2).AsByte()) & 0x8080
Now it depends what do you want to do with the result. Perhaps you don't really need MoveMask, perhaps you need the result in vector format, like normal vector compares provide?

I have a byte array which I iterate through and trying to find matches for a specific value, which itself can be in various data types T, such as long. Matches can be either based on equality, or bigger or smaller. To gain maximum performance I'm casting the byte array into a span of vector128 and then use hardware acceleration of SSE2 to compare.

But I also need to save the position of the match in the original byte array, as well as the matched value as data type T. For this I'm using MoveMask and then TrailingZeroCount and IsBitSet from the BitOps class. This is what I've seen in this repo once and all together is 2-4x times faster than reinterpreting the original byte array as an array of long and iterate through it with a simple loop.

If I just compare two vectors I know if I got a match, but I dont know which of the elements in the vector triggered the match. And calling GetElement for all of them is slower than MoveMask and only call GetElement when needed. Please tell me when I'm wrong and there is a faster and easier way.

cc: @tannergooding

Using MoveMask to get the element which triggered the match and BitOperations.LeadingZeroCount or BitOperations.TrailingZeroCount (the former hardware accelerated on more computers) to get the index of that byte is likely the right thing to do here.

We do similar things in the SpanHelpers class.

Okay thanks :+1: I'm closing this then.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bencz picture bencz  路  3Comments

noahfalk picture noahfalk  路  3Comments

matty-hall picture matty-hall  路  3Comments

GitAntoinee picture GitAntoinee  路  3Comments

iCodeWebApps picture iCodeWebApps  路  3Comments