1

I'm porting a routine written with Intel SSE2 intrinsics to Microsoft 32-bit platforms. It works fine under GCC, Clang and 64-bit Windows. The original code effectively performs the following:

typedef unsigned __int64 word64;

// input is aligned on 16-byte boundary
void (const byte* input)
{
    const word64 m0 = ((const word64*)input)[ 0];
    const word64 m1 = ((const word64*)input)[ 8];
    ...

    __m128 t0 = _mm_set_epi64x(m0, m1);
}

Microsoft does not provide _mm_set_epi64x on 32-bit platforms, so I want to use _mm_set_epi64.

Now the problems... First,

__m64 m0, m1;
m0 = *(word64*)(input+0);

Results in:

1>  error C2679: binary '=' : no operator found which takes a right-hand operand
of type 'word64' (or there is no acceptable conversion)
1>  c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\mmintrin.h(42):
could be '__m64 &__m64::operator =(const __m64 &)'
1>  while trying to match the argument list '(__m64, word64)'

Second, trying to sidestep the potential issue with word64 and use unsigned __int64* directly:

m0 = *(unsigned __int64*)(input+0);

Results in the same:

1>  blake2.cpp(530): error C2679: binary '=' : no operator found which takes a right-hand
operand of type 'unsigned __int64' (or there is no acceptable conversion)

Third, I looked through <mmintrin.h> and found _m_from_int:

m0 = _m_from_int(*(word64*)(input+0));

It results in:

1>  blake2.cpp(529): warning C4244: 'argument' : conversion from 'word64'
to 'int', possible loss of data

I'm not sure what else to try at this point.

How do I load a __m64 from a 64-bit integer type?


Below is Microsoft's declaration of __m64, but we are supposed to treat it as opaque:

typedef union __declspec(intrin_type) _CRT_ALIGN(8) __m64
{
    unsigned __int64    m64_u64;
    float               m64_f32[2];
    __int8              m64_i8[8];
    __int16             m64_i16[4];
    __int32             m64_i32[2];    
    __int64             m64_i64;
    unsigned __int8     m64_u8[8];
    unsigned __int16    m64_u16[4];
    unsigned __int32    m64_u32[2];
} __m64;
jww
  • 97,681
  • 90
  • 411
  • 885
  • http://stackoverflow.com/questions/27258261/msvc-avx-code-compilation-mm256-setr-epi64x/27267287#27267287 – Z boson Apr 18 '16 at 10:52

1 Answers1

1

First I notice that your input is a byte array. When converting from a byte array to a multi-byte binary (like int64) you may need to consider byte order. For purposes of this question I'm going to ignore that issue, but if you get something that "looks wrong" it's something to consider.

In the first error the compiler the compiler is having a problem converting from your dereferenced pointer to a word64 (unsigned __int64). I don't have ready access to the headers but I suspect this may have to do with the 'const'ing. You want a copy operator, but I believe you are getting the assign operator. Same issue for your second compiler error (m0 = (unsigned __int64)(input+0);)

Your third error appears to be caused by _m_to_int expecting a signed int64 and getting an unsigned int64.

I wonder if something like:

const word64 *m0 = ((const word64*)input)[ 0];

or

const word64 m0 = &((const word64*)input);

might work?

Dweeberly
  • 4,668
  • 2
  • 22
  • 41
  • Thanks Dweeberly. If interested, the file is available at [`blake2.cpp`](http://www.cryptopp.com/docs/ref/blake2_8cpp_source.html). The function of interest is `BLAKE2_SSE2_Compress64`. BLAKE2 is little endian. Care must be taken in some places, but not this area because it was intended to run fast on IBM compatibles by using the native byte ordering. – jww Apr 18 '16 at 04:50