18

How to multiply four 32-bit integers by another 4 integers? I didn't find any instruction which can do it.

Paul R
  • 208,748
  • 37
  • 389
  • 560
Yury
  • 1,169
  • 2
  • 16
  • 29

2 Answers2

25

If you need signed 32x32 bit integer multiplication then the following example at software.intel.com looks like it should do what you want:

static inline __m128i muly(const __m128i &a, const __m128i &b)
{
    __m128i tmp1 = _mm_mul_epu32(a,b); /* mul 2,0*/
    __m128i tmp2 = _mm_mul_epu32( _mm_srli_si128(a,4), _mm_srli_si128(b,4)); /* mul 3,1 */
    return _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE (0,0,2,0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE (0,0,2,0))); /* shuffle results to [63..0] and pack */
}

You might want to have two builds - one for old CPUs and one for recent CPUs, in which case you could do the following:

static inline __m128i muly(const __m128i &a, const __m128i &b)
{
#ifdef __SSE4_1__  // modern CPU - use SSE 4.1
    return _mm_mullo_epi32(a, b);
#else               // old CPU - use SSE 2
    __m128i tmp1 = _mm_mul_epu32(a,b); /* mul 2,0*/
    __m128i tmp2 = _mm_mul_epu32( _mm_srli_si128(a,4), _mm_srli_si128(b,4)); /* mul 3,1 */
    return _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE (0,0,2,0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE (0,0,2,0))); /* shuffle results to [63..0] and pack */
#endif
}
Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 3
    Good answer. Funny you made exactly the same typo I had once in my code: It should be _____SSE4_1_____ (no underscore between E and 4). Annoying, because you don't notice it easily - the program runs perfect as long as the alternate code path is ok – Gunther Piez May 08 '12 at 16:00
  • 1
    @drhirsch: thanks for fixing that - in real code I tend to use `__MNI__`, `__SNI__`, etc - mainly for historical reasons, but it's also less prone to simple errors such as the above. – Paul R May 08 '12 at 16:45
  • 1
    Awesome, thanks! Now, if only there was a similar trick for replacing `_mm_insert_epi32` on a CPU with SSE2 only... – Mikhail T. Jul 14 '16 at 21:17
  • Note that the "old CPU path" may be actually slower than an explicit `for` loop over the 4 integers - definitely not faster on my machine. – Ivan Ivanov Jan 12 '17 at 18:11
8

PMULLD, from SSE 4.1, does that.

The description is slightly misleading, it talks about signed multiplication, but since it only stores the lower 32bits, it's really a sign-oblivious instruction that you can use for both, just like IMUL.

harold
  • 61,398
  • 6
  • 86
  • 164