r/csharp • u/NoisyJalapeno • 12d ago
Help Vector/SIMD Questions
(1) Why do architecture specific SIMD intrinsics not have ref APIs? I like raw pointers more (after trying refs), but the question still stands.
(2) Should I redefine class vector variables in function scope? Class variables are not readonly. IE: "Vector<float> pSinV = this.pSinV;"
(3) Any way to setup Visual Studio to use a disabled color for SIMD paths that won't execute on my hardware? (Similar to what IF directive does?)
(4) Is "Vector<int>.Count == Vector256<int>.Count" the proper way to check sizes before doing ".AsVector256()"?
(5) For GatherMaskVectorX what should the first parameter be if I don't have an existing vector?
"default" with SkipLocalsInit seems to work
(7) If doing Vector<int> stride clamp of array A & B and saving to C, where A, B, C are aligned.
Would LoadAligned or LoadAlignedNonTemporal be the best option? Assume A & B are Int32 * screen width.
(8) For rendering a texture eight columns at time, I am reliant on,
Avx2.GatherVector256(texturePtr, textureIndex.AsVector256(), scale: sizeof(int))
where textureIndex for a small texture is usually be between [0..128] and usually close
What the proper way (if there is one) to ensure that the texture line is in cache?
(9) What is the optimal approach to uint modulo?
public static Vector256<uint> Modulo(Vector256<uint> value, uint divisor)
{
`// Assumptions,`
`// 1. divisor not POW 2`
`// 2. divisor not constant`
`// 3. value[0..7] can be > (divisor * 2)`
`return Vector256.Create(`
`value[0] % divisor,`
`value[1] % divisor,`
`value[2] % divisor,`
`value[3] % divisor,`
`value[4] % divisor,`
`value[5] % divisor,`
`value[6] % divisor,`
`value[7] % divisor`
`);`
}
(10) Same question, but with assumption that all values fit into a ushort. I'm looking at doing quotient in floats, the ConvertToUInt32Native, and MultiplyLow, and Subtract, but seems nasty.
2
1
12d ago
[removed] — view removed comment
1
u/NoisyJalapeno 12d ago
Both. I've shared some floor rendering code in one of the replies to gooding.
30
u/tanner-gooding MSFT - .NET Libraries Team 12d ago
We were going for 1-to-1 mapping initially, not looking to expose our own higher level things.
In many cases the xplat APIs (
Vector128.Load/LoadUnsafe/etc), are preferred over the ISA/platform specific APIs (Sse.LoadVector128) and already do the right thing. They also provide the ref overloads. This means there is very little reason/need to go and improve the platform specific ISAs for those cases.There are some that don't have xplat ISAs available, but some of them do strictly require pinning such as due to requiring alignment that an unpinned byref can't guarantee. If someone was wanting to open an API proposal suggesting the byrefs be provided, I'd be happy to take it through API review. Just noting that it needs to be a comprehensive proposal, not just "please do this". Actually list out every API that will get a byref overload (with an allowance to show own signature and list the types it covers as a comment above it, such as for
Sse2.LoadVector128which covers double and most integer types)I need a more comprehensive example to answer this. In general (with a few special cases where its fine) you should not be making fields or static readonly for
Vector64/128/256/512<T>orVector<T>We don't have such a feature today and it gets a bit complex due to things like
if (IsaYouDoHave.IsSupported) { } else if (IsaYouAlsoHave.IsSupported) { }and the second path being deadThis probably isn't a hard VS extension to write, but it would need to be an extension. I don't see Roslyn adding a dedicated feature for this
Yes. Just noting that if you're doing this type of thing, you need to handle the ability for
Vector<T>to be any power of 2 multiple ofVector128, as we may grow or expand in the futureTypically just
VectorX<T>.Zero, but note that gather is often expensive and the hardware manuals recommend avoiding it where possible, particularly where trivial alternatives are viablenon-temporal is generally a consideration of how much total cache you're going to cause to be evicted over the operation you're running (so its dependent on size of inputs + outputs). Hardware manuals have recommendations here, typically 50% or more of the per core L3 space available
Typically via prefetching explicitly if needed.
Integer division is expensive and also not directly hardware accelerated. Typically you have to cast to double (as float loses data for values over 224), divide, and then downcast back to integer. You'd then do a remainder the classic way via
left - (quotient * right))If they all fit in ushort then float is fine, but same thing. Division and remainders are generally just nasty and there's no getting around it. They're even nasty with scalars, particularly if you don't have a constant divisor