Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

_mm256_slli_si256: error "last argument must be an 8-bit intermediate"

Tags:

c

gcc

avx

simd

avx2

I have the following problem (g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4):

When I use _mm256_slli_si256() directly, such as:

__m256i x = _mm256_set1_epi8(0xff);
x = _mm256_slli_si256(x, 3);

the code compiles without problem (g++ -Wall -march=native -O3 -o shifttest shifttest.C).

However, if I wrap it into a function

__m256i doit(__m256i x, const int imm)
{
  return _mm256_slli_si256(x, imm);
}

the compiler complains that

/usr/lib/gcc/x86_64-linux-gnu/4.8/include/avx2intrin.h: In function '__m256i doit(__m256i, int)':
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/avx2intrin.h:651:58: error: the last argument must be an 8-bit immediate
   return (__m256i)__builtin_ia32_pslldqi256 (__A, __N * 8);

regardless of whether the function is used or not.

This can't be a problem with the immediate operand, since the function doit() compiles if I use e.g. _mm256_slli_si32(x, imm) instead, and _mm256_slli_si32() also requires an immediate operand.

There is a related bug report on

https://gcc.gnu.org/bugzilla/show_bug.cgi?format=multiple&id=54825

but it is quite old (2012) and relates to gcc 4.8.0, so I thought the patch would be have been incorporated into g++ 4.8.4 already.

Is there a workaround for this problem?

like image 952
Ralf Avatar asked Jul 09 '15 11:07

Ralf


2 Answers

The argument indicating the number of bits to shift must be a compile-time constant, as it is encoded as an immediate value in the instruction (i.e. not loaded from a register; the actual shift value is part of the instruction encoding). As long as you use it directly, like this:

__m256i x = _mm256_set1_epi8(0xff);
x = _mm256_slli_si256(x, 3);

then the compiler sees the shift value as a compile-time constant, 3. However, when in the context of your wrapping function:

__m256i doit(__m256i x, const int imm)
{
  return _mm256_slli_si256(x, imm);
}

there is no way for the compiler to infer the value of imm at compile time, which is required in order for it to synthesize the shift instruction. The fact that imm is a const int doesn't mean that its value is known at compile time, only that the semantics of the language don't allow it to be modified within the doit() function scope.

It's possible that if doit() were to be inlined by the compiler, then it may be able to statically determine the value of imm and therefore compile successfully, but that may be going too far out on a limb.

If you're using C++, another option would be to make doit() a function template with an argument indicating the shift size, like this:

template <int Shift>
__m256i doit(__m256i x)
{
  return _mm256_slli_si256(x, Shift);
}
like image 113
Jason R Avatar answered Sep 30 '22 19:09

Jason R


The problem is due to your function being public (i.e. callable by functions in other C/C++ modules). If you declare it as static (or inline), the compiler will not do code-generation for this function, and you won't get an error.

like image 25
Marat Dukhan Avatar answered Sep 30 '22 19:09

Marat Dukhan