2

Upon defining a __m128i variable in this manner:

__m128i a;
a.m128i_i32[0] = 65000;

I get the following error:

error: request for member ‘m128i_i32’ in ‘a’, which is of non-class type ‘__m128i {aka __vector(2) long long int}’ a.m128i_i32[0] = 65000;

I have included the followinf header files:

#include <x86intrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
Star
  • 3,222
  • 5
  • 32
  • 48
Blue
  • 653
  • 1
  • 11
  • 26
  • It looks like you’re trying to use an MSVC-specific feature with a different compiler (gcc ?) . – Paul R Dec 19 '17 at 07:56

2 Answers2

6

m128i_i32 is MSVC specific. And you are compiling with GCC or Clang (judging by your error message). Use _mm_setr_epi32 instead.

__m128i a = _mm_setr_epi32(0, 1, 2, 3);
ivaigult
  • 6,198
  • 5
  • 38
  • 66
1

Your code will work under Visual where __m128 is defined as

typedef union __declspec(intrin_type) __declspec(align(16)) __m128i {
__int8              m128i_i8[16];
__int16             m128i_i16[8];
__int32             m128i_i32[4];
__int64             m128i_i64[2];
unsigned __int8     m128i_u8[16];
unsigned __int16    m128i_u16[8];
unsigned __int32    m128i_u32[4];
unsigned __int64    m128i_u64[2];
} __m128i;

so you can access m128_i32, but under g++ __m128 is defined as

typedef long long __m128i __attribute__ ((__vector_size__ (16), __may_alias__));

and your code won't be compiled.

You can assign value by

int32_t* p = (int32_t*)&a;
p[0] = 65000;
rafix07
  • 20,001
  • 3
  • 20
  • 33
  • That worked for me. Thanks. Accessing individual fields is inefficient, isn't it? Is this the right way to go about it? I can also use _mm_setr_epi32, but this is convenient in scenarios where value is dependent on another variable. – Blue Dec 19 '17 at 08:21
  • 3
    Keep in mind that the direct access breaks [strict aliasing rule](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) – ivaigult Dec 19 '17 at 08:23
  • @Blue There are no instructions to set individual fields of `_m128i`, on microsoft page is written `You should not access the __m128i fields directly.` - https://msdn.microsoft.com/en-us/library/26232t5c.aspx. In this way what i wrote, this assign is done by using `mov` instruction, 32 bit data is copied from one place into another, no sse2 is taken to do this assign. In order to set all 4 ints use `_mm_set_epi32`. – rafix07 Dec 19 '17 at 08:34
  • So I cant use `int32_t* p = (int32_t*)&a;p[3] = 65000;` ? `a` is stored sequentially in memory right? Even though SSE is not being used, it does the job, right? – Blue Dec 19 '17 at 08:35
  • @Blue Yep, `a` has 16 bytes and is stored sequentially, when accesing `a[3]` last 4 bytes will be filled by data. To set this data no sse2 instructions is used. But `strict aliasing rule` was mentioned that it may be a problem, but I think this code should work, because _m128i was defined with `__attribute__ (__may_alias__)`. – rafix07 Dec 19 '17 at 09:25
  • @Blue and rafix: `__may_alias__` only works one way: it's legal to cast the address of an `int32_t` to `(__m128i*)`, but *not* vice versa. For type-punning the other way, you need to use a union or memcpy. Or for this problem with SSE4.1, use `_mm_insert_epi32(vec, scalar, position)` (where position must be a compile-time constant). To get the compiler to generate shuffles for you without SSE4.1 intrinsics, use a `union { __m128i v; int32_t i32[4]; };` Or define your own vector type based on `int32_t` instead of `long long` wtih `__vector_size__ (16)` and use `v[2] = 65000`. – Peter Cordes Dec 19 '17 at 18:59
  • @PeterCordes Oh it only goes one way? I actually didn't know that. Thanks! – Mysticial Dec 20 '17 at 17:27
  • @Mysticial: IIRC, that's what Marc Glisse (or maybe another gcc dev) told me in an SO comment some other time this came up, when I was wondering if it was safe to use `int*` on the elements of a vector. – Peter Cordes Dec 20 '17 at 18:57