I have exactly this problem. It is reasonably easy to convert to SoA using something like this:
struct tComplexFloat
{
float Real;
float Imag;
};
static inline tComplexFloat ReadFromArrayOfComplexFloat(
uniform const tComplexFloat Input[], int32 Index
)
{
const uint64 Raw = ((uniform uint64 *)Input
)[Index];
float Imag = floatbits((uint32)(Raw >> 32));
float Real = floatbits((uint32)(Raw & 0xFFFFFFFF));
const tComplexFloat Value = {Real, Imag};
return Value;
}
...
foreach(i = 0...N)
{
tComplexFloat Value =
ReadFromArrayOfComplexFloat(InputData, i);
// Operate on
Value
}
However, while this might be more efficient than using a gather, it is still significantly less efficient than hand-coded (with the FMADDSUB, in our case) C+intrinsics.
This is the main reason why we are still using intrinsics, instead of ISPC, for a lot of our code. However, I don't see how ISPC could make use of the ADDSUB instructions, due to the programming model. You could, of course, manually swap values between program instances and work on them that way but this would be complicated and likely to result in code just as difficult to write and understand as using intrinsics.
I would also be very interested to learn if there is a way around this.
Regards,
S.