Message ID | 001101d7c337$1db55680$59200380$@nextmovesoftware.com |
---|---|
State | New |
Headers | show |
Series | Constant fold SS_NEG and SS_ABS in simplify-rtx.c | expand |
On 10/17/2021 3:12 AM, Roger Sayle wrote: > 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; > > > This patch has been tested on x86_64-pc-linux-gnu with "make bootstrap" > and "make -k check" with no new failures. Ok for mainline? > > > 2021-10-17 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. OK. Jeff
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index e4fae0b..2bb18fb 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -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;