I'm struggling to find the right C++/clang utterance to solve the following problem. Notice first that the following doesn't overflow the unsigned short because of integer promotions before the arithmetic happens.
unsigned short testme = 16320;
testme = testme * 257 / 64;
The result is 65535. But when I use simd to try something similar on a vector of unsigned shorts, it doesn't work:
#import <simd/simd.h>
template <typename T>
void muldiv( T* data, unsigned multiply, unsigned divide)
{
*data = (*data * multiply) / divide;
}
...
simd::ushort4 testme = 16320;
muldiv( &testme, 257, 64);
This gives a vector of four 1023's. No integer promotion happened and the multiply wrapped. After looking about in the clang docs, the best I could come up with is this. Notice the caller has to provide a dummy parameter just to provide the working precision as a template type parameter.
#import <simd/simd.h>
template <typename T, typename W>
void muldiv( T* data, unsigned multiply, unsigned divide, W workingtype)
{
*data = __builtin_convertvector( (__builtin_convertvector(*data, W) * multiply) / divide, T);
}
...
simd::ushort4 testme = 16320;
muldiv( &testme, 257, 64, simd::uint4());
Now I get a vector of four 65535's. The reason T is a template parameter is sometimes I pass ushort4, ushort8, ushort16, etc. But I find it ugly to pass the working precision as a parameter as it is always unsigned int. I can't figure out a way to extract the simd-length from T so I can declare the type W locally. Something like this within the function would be nice:
typedef unsigned int W __attribute__((__vector_size__( ?? )));
But I can't figure out how to make that work. I tried something like this:
bool hopeful = __is_convertible_to( simd::ushort4, simd::uint4);
But hopeful always returns false.
Can anyone tell me the magic I need?
Note this is on Apple platforms which provides <simd/simd.h>.