[SIMD] Pre-review questions
Hello, I have several questions regarding Boost.SIMD (for pre-review) 1. What is boost::simd::pack::storage_type I can't find it in documentation. Is it the "native register" like __m128i for pack<int,4>? If the answer is no, how do I get access to underlying type? 2. I can't find in documentation how to performs casts between different types: I see in docs split_low (actually after I grepped for _mm_unpacklo) but I failed to find how to use one - there is no documentation regarding conversion/casting operation or at least I failed to find one. 3. Is there more convenient way to perform basic saturated operation for example if I want to calc abs diff of two bs::pack<unsigned char,16> values a,b I need to write bs::saturated_(be::minus)(a,b) + bs::saturated_(bs::minus)(b,a) It is quite inconvenient especially when most of operations you want to do are saturated. 4. Why Boost.SIMD is restricted to C++11? Most of the stuff is implementable withing C++2003, it severely limits the usability of the library for existing projects that can't trivially switch to new C++ standard (and there are too many in the "real world" industry) Thanks, Artyom
On 26/03/2017 08:37, Artyom Beilis via Boost wrote:
Hello,
I have several questions regarding Boost.SIMD (for pre-review)
1. What is boost::simd::pack::storage_type I can't find it in documentation. Is it the "native register" like __m128i for pack<int,4>? If the answer is no, how do I get access to underlying type?
It is indeed as explained the concept pages : https://developer.numscale.com/boost.simd/documentation/develop/struct_vecto... No, usually you should not rely on this as : - it may be something else entirely depending on type/cardinal including a pair of pack or a array o scalar when you're forced to emulate some cases. - pack is automatically casted in the proper _m* type if you really really need to write call to a platform specific intrinsic (which should not be happening a lot anyway). - pack can also be constructed from or assigned a _m* type automatically. What you may want is to know statically in generic contexts is if a pack is actually stored "natively", something the has_native_storage metafunction should tell you (doc is not up but will be next round of updates).
2. I can't find in documentation how to performs casts between different types: I see in docs split_low (actually after I grepped for _mm_unpacklo) but I failed to find how to use one - there is no documentation regarding conversion/casting operation or at least I failed to find one.
The function you look for is pack_cast https://developer.numscale.com/boost.simd/documentation/develop/group__group... pack<float,8>
3. Is there more convenient way to perform basic saturated operation for example if I want to calc abs diff of two bs::pack<unsigned char,16> values a,b I need to write
bs::saturated_(be::minus)(a,b) + bs::saturated_(bs::minus)(b,a)
It is quite inconvenient especially when most of operations you want to do are saturated.
All functions in Boost.SIMD are function object. Decorators just wrap them in a proper layer. So auto sm = bs::saturated_(be::minus); sm(a,b) + sm(b,a); is the recommended way to do it. Then in your specific example, you can use dist that do the proper computation without calling the saturated costly version of minus. IF you really want to handle saturation, in case of handling INT_MAX and INT_MIN then call saturated_(dist). Usually, we strongly advice the use of the highest-level possible function instead of trying to just rewrite an old SSE* code using one-for-one intrinsic mapping. Boost.SIMD wraps a lot of well known tricks and optimization in high level version of said function in order to give access to those to all users.
4. Why Boost.SIMD is restricted to C++11? Most of the stuff is implementable withing C++2003, it severely limits the usability of the library for existing projects that can't trivially switch to new C++ standard (and there are too many in the "real world" industry)
Different reasons: - It was written like that initially and supporting old compilers was not worth our time at the moment. C++11 helps us to write interface the correct way without requiring to compile-time costly macros or similar prehistoric tricks. It also enable us to have fancy trick like the "use constexpr permutation function in shuffle" etc ... - we are in 2017 and most of our users - including our "real world industry" customers - are OK with using C++11. Migrating to C++11 6 years after the standardization should not be a constraints as most compilers now support it. We're proposing it to Boost, which is still, in our mind, the one place to push forward the language not supporting decades old compilers. Best regards
On Sun, Mar 26, 2017 at 3:05 PM, Joel FALCOU via Boost <boost@lists.boost.org> wrote:
On 26/03/2017 08:37, Artyom Beilis via Boost wrote:
2. I can't find in documentation how to performs casts between different types: I see in docs split_low (actually after I grepped for _mm_unpacklo) but I failed to find how to use one - there is no documentation regarding conversion/casting operation or at least I failed to find one.
The function you look for is pack_cast
https://developer.numscale.com/boost.simd/documentation/develop/group__group...
pack<float,8>
Still do you have examples or documentation for: How do I cast for example low part or high part something like: pack<unsigned byte,16> v; pack<unsigned short,8> v1=cast_low(v); // note sometimes I indeed need only low or only high part - not both pack<unsigned short,8> v2=cast_high(v); ... v=join_cast(v1,v2); // short to byte What is saturation policy: if I have unsigned short of value 257 casted to unsigned char would it cast to 1 or to 255? How can I control the policy?
3. Is there more convenient way to perform basic saturated operation for example if I want to calc abs diff of two bs::pack<unsigned char,16> values a,b I need to write
bs::saturated_(be::minus)(a,b) + bs::saturated_(bs::minus)(b,a)
It is quite inconvenient especially when most of operations you want to do are saturated.
All functions in Boost.SIMD are function object. Decorators just wrap them in a proper layer. So
auto sm = bs::saturated_(be::minus); sm(a,b) + sm(b,a);
is the recommended way to do it.
I see
Then in your specific example, you can use dist that do the proper computation without calling the saturated costly version of minus. IF you really want to handle saturation, in case of handling INT_MAX and INT_MIN then call saturated_(dist).
Usually, we strongly advice the use of the highest-level possible function instead of trying to just rewrite an old SSE* code using one-for-one intrinsic mapping. Boost.SIMD wraps a lot of well known tricks and optimization in high level version of said function in order to give access to those to all users.
I agree I searched for something like absdiff but didn't found the "dist" function - but indeed it is better. Thanks, Artyom
On 26/03/2017 15:28, Artyom Beilis via Boost wrote:
Still do you have examples or documentation for:
How do I cast for example low part or high part something like:
pack<unsigned byte,16> v; pack<unsigned short,8> v1=cast_low(v); // note sometimes I indeed need only low or only high part - not both pack<unsigned short,8> v2=cast_high(v); ... v=join_cast(v1,v2); // short to byte
What is saturation policy: if I have unsigned short of value 257 casted to unsigned char would it cast to 1 or to 255? How can I control the policy?
If you only need part of it, it's not a cast, it's a split as cast preserve cardinality of pack. pack<unsigned byte,16> v; pack<unsigned short,8> v1=split_low(v); pack<unsigned short,8> v2=split_high(v); and if you need both : pack<unsigned byte,16> v; auto vs = split(v); and vs[0],vs[1] are the low and high parts respectively. IIRC split has no saturation policy as saturation is what we use when you go down the type. You can rebuild a smaller type using group or saturated_(group). You also have slice that slice a pack in two, keeping the type but reducing the cardinal. combine do the reverse. Considering this complexity, most of the common use-cases are handled by pack_cast already, leaving direct call to split_* for more advanced usages. As for the doc, thanks for raising an actual bug, the doc is not indeed properly included. Will fix this. Maybe a tutorial about pack_cast,slice,split,group and combine is indeed needed.
participants (2)
-
Artyom Beilis
-
Joel FALCOU