Question

I would like to let the compiler choose registers automatically by parameter-izing my inline assembly in my C code, but I'm having some trouble. Can anyone tell me what is going wrong? If I use the code that I have commented out (forcing the affiliation with %xmm0), it will compile and get the expected result. But if I leave it commented out as written here, I get the compiler error:

/tmp/ccJxmSbm.s: Assembler messages:
/tmp/ccJxmSbm.s:81: Error: the first operand of `blendvpd' must be `%xmm0'

Also, if I do nothing other than remove the printf statement, the code block compiles successfully too. So it has something to do with moving parameters around to prepare for the printf call. I have explicitly put in the "Yz" constraint which is supposed to force the use of %xmm0, but it looks like it is not being honored.

Here is the code in question:

#include <stdio.h>

const unsigned long long myConst[2]  = {0x0000000000000000,0xffffffffffffffff};
const unsigned long long myConst2[2] = {0x0000000000000000,0x1111111111111111};
const unsigned long long myConst3[2] = {0x0123456789abcdef,0x0000000000000000};

#define ASSIGN_CONST128( val, const ) \
  val = *((__uint128_t *)const);

int main( void )
{
  register __uint128_t regVal1 /* asm("%xmm0") */ ;
  register __uint128_t regVal2;
  register __uint128_t regVal3;
  ASSIGN_CONST128( regVal1, myConst );
  ASSIGN_CONST128( regVal2, myConst2 );
  ASSIGN_CONST128( regVal3, myConst3 );

  asm( "blendvpd %[mask], %[val1], %[val2]" :
       [val2] "+x" (regVal3) :
       [mask] "Yz" (regVal1),
       [val1] "x"  (regVal2) );

  printf( "REGVAL1: %016llx%016llx (original=%016llx%016llx)\n"
          "REGVAL2: %016llx%016llx (original=%016llx%016llx)\n"
          "REGVAL3: %016llx%016llx (original=%016llx%016llx)\n",
   (unsigned long long)(regVal1>>64), (unsigned long long)regVal1,
   myConst[1], myConst[0],
   (unsigned long long)(regVal2>>64), (unsigned long long)regVal2,
   myConst2[1], myConst2[0],
   (unsigned long long)(regVal3>>64), (unsigned long long)regVal3,
   myConst3[1], myConst3[0] );

  // Expected result:
  // REGVAL1: ffffffffffffffff0000000000000000 (original=ffffffffffffffff0000000000000000)
  // REGVAL2: 11111111111111110000000000000000 (original=11111111111111110000000000000000)
  // REGVAL3: 11111111111111110123456789abcdef (original=00000000000000000123456789abcdef)
}

I appreciate any thoughts.

Was it helpful?

Solution

Why not just use the relevant intrinsic?

regVal3 = _mm_blendv_pd (regVal1, regVal2, regVal3);

As others have noted, regVal1, regVal2 and regVal3 should all be declared as __m128d.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top