0

We're trying to make a vector intrinsic library of different operations and one of them is getting the absolute value of the number. However, my professor limited it to double only.

I'm fairly new to the x86 intrinsics instruction set, so I was hoping someone can enlighten me.

This is what I have so far:

 void vectorAbs(double *x, double *y, unsigned int N);
 int main()
 {
     double x[] = { -1, -2, -3, -4, -5, -6 };
     double y[] = { 2, 2, 2, 2, 2, 2 };
     double *pX = x, *pY = y;

     vectorAbs(pX, pY, 6);
 }

 void vectorAbs(double *x, double *y, unsigned int N)
 {
     __m128d xVar;
     __m128d yVar;

     printf("\nSquare of x : \n");
     for (int i = 0; i < N; i += 2)
     {
       xVar = _mm_loadu_pd(&x[i]);  // load *x[i] to xVar 

       yVar = _mm_abs_epi16(xVar); // abs of x
       _mm_storeu_pd(&y[i], yVar); // store yVar to y[i]

       printf("%lf, %lf, ", y[i], y[i + 1]);
     }
     system("pause");

}

And the error I'm getting is:

no operator "=" matches these operands

operand types are: __m128d = __m128i

Community
  • 1
  • 1
nutellafella
  • 135
  • 1
  • 4
  • 17
  • `_mm_abs_epi16` calculates absolute values of *16-bit integers* – T.C. Aug 31 '14 at 09:32
  • oh, accdg to my cheat sheet, it can only do up to 32-bit integers. but we're required to use 128 bits. will that be an issue? because my main problem is how to convert my double into an int so it can get the absolute value. or how to get the absolute value of a double, basically. – nutellafella Aug 31 '14 at 09:38
  • It treats the 128 bits as 8 signed 16-bit integers and calculate the absolute value of each - which is definitely not what you want. Conversion to integers obviously loses lots of information. You should probably implement absolute value yourself in more elementary operations - compare to zero, and then negate/subtract from zero if it's less than zero, etc. – T.C. Aug 31 '14 at 09:50

1 Answers1

4

All you need to do is clear the sign bit of the two double values in the vector. The sign bits of each double are in vector bit positions 63 and 127. This can be done with a single instruction (andpd) by using the intrinsic function _mm_and_pd. Another way is to logical shift the two doubles left one bit and then right one bit. The two values can be shifted in parallel using the _mm_slli_epi64 and _mm_srli_epi64 intrinsic functions. Here is an example:

#include <stdio.h>
#include <stdlib.h>
#include <intrin.h>

 void vectorAbs(double *x, double *y, unsigned int N);
 int main()
 {
     double x[] = { -1, -2, -3, -4, -5, -6 };
     double y[] = { 2, 2, 2, 2, 2, 2 };
     double *pX = x, *pY = y;

     vectorAbs(pX, pY, 6);
 }

__m128d abs_sample1 (__m128d val)
    {
    return _mm_castsi128_pd (_mm_srli_epi64 (_mm_slli_epi64 (_mm_castpd_si128 (val), 1), 1));
    }

__m128d abs_sample2 (__m128d val)
    {
    const __m128d mask = _mm_castsi128_pd (_mm_set1_epi64x (0x7FFFFFFFFFFFFFFF));
    return _mm_and_pd (mask, val);
    }

 void vectorAbs(double *x, double *y, unsigned int N)
 {
     __m128d xVar;
     __m128d yVar;

     printf("\nSquare of x : \n");
     for (int i = 0; i < N; i += 2)
     {
       xVar = _mm_loadu_pd(&x[i]);  // load *x[i] to xVar 

       yVar = abs_sample1(xVar); // abs of x
       _mm_storeu_pd(&y[i], yVar); // store yVar to y[i]
       printf("%lf, %lf, ", y[i], y[i + 1]);
     }
     system("pause");

}
  • `__m128d mask = _mm_castsi128_pd(_mm_setr_epi32(-1,0x7FFFFFFF,-1,0x7FFFFFFF)); yVar = _mm_and_pd(xVar,mask);` – Z boson Sep 04 '14 at 15:41