]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Constant fold SS_NEG and SS_ABS in simplify-rtx.c
authorRoger Sayle <roger@nextmovesoftware.com>
Mon, 18 Oct 2021 10:51:07 +0000 (11:51 +0100)
committerRoger Sayle <roger@nextmovesoftware.com>
Mon, 18 Oct 2021 10:51:07 +0000 (11:51 +0100)
This simple patch performs compile-time constant folding of
signed saturating negation and signed saturating absolute value
in the RTL optimizers.  Normally in two's complement arithmetic
the lowest representable signed value overflows on negation,
With these saturating operators they "saturate" to the maximum
representable signed value, so SS_NEG:QI -128 is 127, and
SS_ABS:HI -32768 is 32767.

On bfin-elf, the following two short functions:

short foo()
{
  short t = -32768;
  short r = __builtin_bfin_negate_fr1x16(t);
  return r;
}

int bar()
{
  int t = -2147483648;
  int r = __builtin_bfin_abs_fr1x32(t);
  return r;
}

currently compile to:
_foo: nop;
        nop;
        R0 = -32768 (X);
        R0 = -R0 (V);
        rts;

_bar: nop;
        R0 = -1 (X);
        R0 <<= 31;
        R0 = abs R0;
        rts;

but with this middle-end patch now compile to:

_foo: nop;
        nop;
        nop;
        R0 = 32767 (X);
        rts;

_bar: nop;
        nop;
        R0 = -1 (X);
        R0.H = 32767;
        rts;

2021-10-18  Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
* simplify-rtx.c (simplify_const_unary_operation) [SS_NEG, SS_ABS]:
Evalute SS_NEG and SS_ABS of a constant argument.

gcc/testsuite/ChangeLog
* gcc.target/bfin/ssabs.c: New test case.
* gcc.target/bfin/ssneg.c: New test case.

gcc/simplify-rtx.c
gcc/testsuite/gcc.target/bfin/ssabs.c [new file with mode: 0644]
gcc/testsuite/gcc.target/bfin/ssneg.c [new file with mode: 0644]

index e4fae0b3e57fb0f8ff3f7237ac74b7548ffe60d8..2bb18fb506547698df158bdb5123268aa96ae261 100644 (file)
@@ -2026,6 +2026,20 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
          result = wide_int::from (op0, width, SIGNED);
          break;
 
+       case SS_NEG:
+         if (wi::only_sign_bit_p (op0))
+           result = wi::max_value (GET_MODE_PRECISION (imode), SIGNED);
+         else
+           result = wi::neg (op0);
+         break;
+
+       case SS_ABS:
+         if (wi::only_sign_bit_p (op0))
+           result = wi::max_value (GET_MODE_PRECISION (imode), SIGNED);
+         else
+           result = wi::abs (op0);
+         break;
+
        case SQRT:
        default:
          return 0;
diff --git a/gcc/testsuite/gcc.target/bfin/ssabs.c b/gcc/testsuite/gcc.target/bfin/ssabs.c
new file mode 100644 (file)
index 0000000..e9d8bae
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int foo()
+{
+  int t = -2147483648;
+  int r = __builtin_bfin_abs_fr1x32(t);
+  return r;
+}
+
+/* { dg-final { scan-assembler "32767" } } */
diff --git a/gcc/testsuite/gcc.target/bfin/ssneg.c b/gcc/testsuite/gcc.target/bfin/ssneg.c
new file mode 100644 (file)
index 0000000..44ad7ed
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+short foo()
+{
+  short t = -32768;
+  short r = __builtin_bfin_negate_fr1x16(t);
+  return r;
+}
+
+/* { dg-final { scan-assembler "32767" } } */