switch (mode)
{
+ case E_V2DImode:
+ case E_V4DImode:
+ /* For 64-bit signed integer X, with SSE4.2 use
+ pxor t0, t0; pcmpgtq X, t0; pxor t0, X; psubq t0, X.
+ Otherwise handle it similarly to V4SImode, except use 64 as W instead of
+ 32 and use logical instead of arithmetic right shift (which is
+ unimplemented) and subtract. */
+ if (TARGET_SSE4_2)
+ {
+ tmp0 = gen_reg_rtx (mode);
+ tmp1 = gen_reg_rtx (mode);
+ emit_move_insn (tmp1, CONST0_RTX (mode));
+ if (mode == E_V2DImode)
+ emit_insn (gen_sse4_2_gtv2di3 (tmp0, tmp1, input));
+ else
+ emit_insn (gen_avx2_gtv4di3 (tmp0, tmp1, input));
+ }
+ else
+ {
+ tmp0 = expand_simple_binop (mode, LSHIFTRT, input,
+ GEN_INT (GET_MODE_UNIT_BITSIZE (mode)
+ - 1), NULL, 0, OPTAB_DIRECT);
+ tmp0 = expand_simple_unop (mode, NEG, tmp0, NULL, false);
+ }
+
+ tmp1 = expand_simple_binop (mode, XOR, tmp0, input,
+ NULL, 0, OPTAB_DIRECT);
+ x = expand_simple_binop (mode, MINUS, tmp1, tmp0,
+ target, 0, OPTAB_DIRECT);
+ break;
+
+ case E_V4SImode:
/* For 32-bit signed integer X, the best way to calculate the absolute
value of X is (((signed) X >> (W-1)) ^ X) - ((signed) X >> (W-1)). */
- case E_V4SImode:
- tmp0 = expand_simple_binop (mode, ASHIFTRT, input,
- GEN_INT (GET_MODE_UNIT_BITSIZE (mode) - 1),
- NULL, 0, OPTAB_DIRECT);
- tmp1 = expand_simple_binop (mode, XOR, tmp0, input,
- NULL, 0, OPTAB_DIRECT);
- x = expand_simple_binop (mode, MINUS, tmp1, tmp0,
- target, 0, OPTAB_DIRECT);
- break;
+ tmp0 = expand_simple_binop (mode, ASHIFTRT, input,
+ GEN_INT (GET_MODE_UNIT_BITSIZE (mode) - 1),
+ NULL, 0, OPTAB_DIRECT);
+ tmp1 = expand_simple_binop (mode, XOR, tmp0, input,
+ NULL, 0, OPTAB_DIRECT);
+ x = expand_simple_binop (mode, MINUS, tmp1, tmp0,
+ target, 0, OPTAB_DIRECT);
+ break;
+ case E_V8HImode:
/* For 16-bit signed integer X, the best way to calculate the absolute
value of X is max (X, -X), as SSE2 provides the PMAXSW insn. */
- case E_V8HImode:
- tmp0 = expand_unop (mode, neg_optab, input, NULL_RTX, 0);
+ tmp0 = expand_unop (mode, neg_optab, input, NULL_RTX, 0);
- x = expand_simple_binop (mode, SMAX, tmp0, input,
- target, 0, OPTAB_DIRECT);
- break;
+ x = expand_simple_binop (mode, SMAX, tmp0, input,
+ target, 0, OPTAB_DIRECT);
+ break;
+ case E_V16QImode:
/* For 8-bit signed integer X, the best way to calculate the absolute
value of X is min ((unsigned char) X, (unsigned char) (-X)),
as SSE2 provides the PMINUB insn. */
- case E_V16QImode:
- tmp0 = expand_unop (mode, neg_optab, input, NULL_RTX, 0);
+ tmp0 = expand_unop (mode, neg_optab, input, NULL_RTX, 0);
- x = expand_simple_binop (V16QImode, UMIN, tmp0, input,
- target, 0, OPTAB_DIRECT);
- break;
+ x = expand_simple_binop (V16QImode, UMIN, tmp0, input,
+ target, 0, OPTAB_DIRECT);
+ break;
- default:
- gcc_unreachable ();
+ default:
+ gcc_unreachable ();
}
if (x != target)
--- /dev/null
+// PR target/85572
+// { dg-do run { target i?86-*-* x86_64-*-* } }
+// { dg-options "-O2 -msse2" }
+// { dg-require-effective-target sse2_runtime }
+
+typedef long long V __attribute__((vector_size (16)));
+typedef long long W __attribute__((vector_size (32)));
+
+__attribute__((noipa)) V
+foo (V x)
+{
+ return x < 0 ? -x : x;
+}
+
+__attribute__((noipa)) void
+bar (W *x, W *y)
+{
+ *y = *x < 0 ? -*x : *x;
+}
+
+int
+main ()
+{
+ V a = { 11LL, -15LL };
+ V b = foo (a);
+ if (b[0] != 11LL || b[1] != 15LL)
+ __builtin_abort ();
+ V c = { -123456789123456LL, 654321654321654LL };
+ V d = foo (c);
+ if (d[0] != 123456789123456LL || d[1] != 654321654321654LL)
+ __builtin_abort ();
+ V e = { 0, 1 };
+ V f = foo (e);
+ if (f[0] != 0 || f[1] != 1)
+ __builtin_abort ();
+ W g = { 17LL, -32LL, -123456789123456LL, 654321654321654LL }, h;
+ bar (&g, &h);
+ if (h[0] != 17LL || h[1] != 32LL
+ || h[2] != 123456789123456LL || h[3] != 654321654321654LL)
+ __builtin_abort ();
+ W i = { 0, 1, -1, 0 }, j;
+ bar (&i, &j);
+ if (j[0] != 0 || j[1] != 1 || j[2] != 1 || j[3] != 0)
+ __builtin_abort ();
+}