Kyrylo Tkachov via Gcc-patches <gcc-patches@gcc.gnu.org> writes: > Hi all, > > This patch implements RTL constant-folding for the SS_TRUNCATE and > US_TRUNCATE codes. > The semantics are a clamping operation on the argument with the min and max > of the narrow mode, > followed by a truncation. The signedness of the clamp and the min/max extrema > is derived from > the signedness of the saturating operation. > > We have a number of instructions in aarch64 that use SS_TRUNCATE and > US_TRUNCATE to represent > their operations and we have pretty thorough runtime tests in > gcc.target/aarch64/advsimd-intrinsics/vqmovn*.c. > With this patch the instructions are folded away at optimisation levels and > the correctness checks still > pass. > > Bootstrapped and tested on aarch64-none-linux-gnu and aarch64_be-none-elf. > Ok for trunk? > > Thanks, > Kyrill > > gcc/ChangeLog: > > * simplify-rtx.cc (simplify_const_unary_operation): > Handle US_TRUNCATE, SS_TRUNCATE. > > diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc > index > 276be67aa67247dd46361ab9badc46ab089d6df0..5983a06e5a8ca89c717e8648be410024147b16e6 > 100644 > --- a/gcc/simplify-rtx.cc > +++ b/gcc/simplify-rtx.cc > @@ -2131,6 +2131,22 @@ simplify_const_unary_operation (enum rtx_code code, > machine_mode mode, > result = wide_int::from (op0, width, UNSIGNED); > break; > > + case US_TRUNCATE: > + case SS_TRUNCATE: > + { > + signop sgn = code == US_TRUNCATE ? UNSIGNED : SIGNED; > + wide_int nmax > + = wide_int::from (wi::max_value (width, sgn), > + GET_MODE_PRECISION (imode), sgn); > + wide_int nmin > + = wide_int::from (wi::min_value (width, sgn), > + GET_MODE_PRECISION (imode), sgn); > + result > + = wide_int::from (op0, GET_MODE_PRECISION (imode), sgn); > + result = wi::min (wi::max (result, nmin, sgn), nmax, sgn);
FWIW, it looks like this could be: result = wi::min (wi::max (op0, nmin, sgn), nmax, sgn); without the first assignment to result. That feels more natural IMO, since no conversion is being done on op0. Thanks, Richard > + result = wide_int::from (result, width, sgn); > + break; > + } > case SIGN_EXTEND: > result = wide_int::from (op0, width, SIGNED); > break;