https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128561
Bug ID: 128561
Summary: rs6000: _mm_mullo_epi16 (x, 3) / 3 is folded to x
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: yuki.tanaka at defaultcase dot de
Target Milestone: ---
#define NO_WARN_X86_INTRINSICS 1
#include <emmintrin.h>
#include <stdint.h>
typedef int16_t v8hi __attribute__((vector_size(16)));
__attribute__((noipa)) v8hi a(__m128i b)
{
return (v8hi)_mm_mullo_epi16(b, _mm_set1_epi16(3)) / 3;
}
int main(void)
{
int16_t in[8] = {0x5555, 0x7fff, 0x2aab, 1, 0, -1, -0x5555, 100};
v8hi r = a(_mm_loadu_si128((__m128i *)in));
for (int i = 0; i < 8; i++)
{
int16_t p = (int16_t)(uint16_t)(in[i] * 3);
if (r[i] != p / 3)
__builtin_abort();
}
return 0;
}
_mm_mullo_epi16 returns the low 16 bits of each product, so the multiplication
wraps. For the lane 0x5555, 0x5555 * 3 = 0xFFFF, which is -1 as int16_t, and -1
/ 3 = 0. The program must return normally.
With -O2 the function a is compiled to a bare blr: the multiplication and the
division are gone. The argument is returned unchanged, so lane 0 is 0x5555
instead of 0, and the check in main would abort. This happens on GCC 15.2.0,
16.1.0 and trunk. I do not have a PowerPC machine, so I could not run the
program, the result is derived from the generated code.
This is specific to PowerPC (powerpc64le, config/rs6000). The same program
without the NO_WARN_X86_INTRINSICS define passes on x86-64 with -O2.
The PowerPC header multiplies signed vectors: gcc/config/rs6000/emmintrin.h has
_mm_mullo_epi16 return (__m128i) ((__v8hi)__A * (__v8hi)__B). Signed overflow
of a vector element is undefined, so (x * 3) / 3 is folded to x. The x86 header
uses __v8hu here.
Compiler Explorer:
https://godbolt.org/z/1o9Pf6Woo