0

The below code works fine with Xcode:

const __m128d source      = { x, y };
const double  destination = source[0];    // Read the "x" from "source"

In latest version of Visual Studio I get the following error message from the compiler: ---> No operator "[]" matches these operands.

According to all examples I've found from the web the above should be the standard way of accessing those components inside __m128d, so what is causing the error and how to fix it?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 2
    Xcode and Visual Studio are just IDEs. The error is from a compiler – 463035818_is_not_an_ai May 23 '22 at 09:29
  • I know, but that doesn't answer my question. – user19179144 May 23 '22 at 09:44
  • 4
    if you know that you should say what compilers you are using rather than just the IDEs. No its not an answer, its just a comment. – 463035818_is_not_an_ai May 23 '22 at 09:45
  • 1
    [_"You should not access the `__m128d` fields directly"_](https://learn.microsoft.com/en-us/cpp/cpp/m128d?view=msvc-170) – Ted Lyngmo May 23 '22 at 10:20
  • 1
    Very related: https://stackoverflow.com/questions/19359372/mm-cvtsd-f64-analogon-for-higher-order-floating-point. TLDR use `_mm_cvtsd_f64` – Mike Vine May 23 '22 at 10:30
  • Yeah, that's expected. MSVC defines intrinsics as a union, not using GNU C vector extensions because it doesn't support them. The Intel intrinsics API doesn't document either `[]` or `.f64[]` or whatever MSVC calls it, which is why they aren't portable. See [print a \_\_m128i variable](https://stackoverflow.com/a/46752535) re: accessing all the elements, otherwise use a shuffle and get the low element with `_mm_cvtsd_f64` – Peter Cordes May 23 '22 at 14:03
  • Basically a duplicate of [Get member of \_\_m128 by index?](https://stackoverflow.com/q/12624466) which is about `__m128` (packed single) vectors. The change to a `double arr[2]` union, or to `_mm_shuffle_pd` instead of `ps` should be fairly obvious. – Peter Cordes May 23 '22 at 14:16

1 Answers1

1

The source[i] syntax is a GCC/Clang extension which does not work with MSVC.

To extract the lower double component of a __m128d vector use

double lower = _mm_cvtsd_f64(source);

For the upper component, you need to first move it to the lower part, e.g., using:

double higher = _mm_cvtsd_f64( // extract value
                  _mm_castps_pd( // reinterpret as __m128d
                    _mm_movehl_ps( // move high half of second argument to lower half
                      _mm_setzero_ps(), // could be an arbitrary vector 
                      _mm_castpd_ps(source)
                ) ) );

Instead of _movehl_ps you could also use a _mm_shuffle_pd instruction. Also, if you actually intend to store the upper element to memory, you could use:

double dest;   // target somewhere in memory
_mm_storeh_pd(&dest, source);
chtz
  • 17,329
  • 4
  • 26
  • 56
  • 1
    If you're going to use a `pd` shuffle, `_mm_unpackhi_pd(v,v)` is strictly better than `_mm_shuffle_pd(v,v, 0b11)` to broadcast the high half. Smaller code-size since there's no immediate, and both need the vector as both inputs, so without AVX they destroy the original, maybe forcing the compiler to copy it if you still need it. Of course clang will optimize either one to whatever it thinks is best, but some compilers (especially MSVC) take intrinsics more literally. – Peter Cordes May 23 '22 at 21:11
  • 1
    Neither of these support runtime-variable indexing; AVX `vpermilps` could do that, or store/reload. See also [Get member of \_\_m128 by index?](https://stackoverflow.com/q/12624466) for union hacks, or store to a tmp array is usually easier as in [print a \_\_m128i variable](https://stackoverflow.com/a/46752535) and either one will be optimized by the compiler to maybe not actually store, especially for a constant index. – Peter Cordes May 23 '22 at 21:13