diff options
Diffstat (limited to 'gcc/simplify-rtx.c')
-rw-r--r-- | gcc/simplify-rtx.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 4f0652f..869f0d1 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -1527,6 +1527,38 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op) && XEXP (op, 1) != const0_rtx) return simplify_gen_unary (ZERO_EXTEND, mode, op, GET_MODE (op)); + /* (sign_extend:M (truncate:N (lshiftrt:O <X> (const_int I)))) where + I is GET_MODE_PRECISION(O) - GET_MODE_PRECISION(N), simplifies to + (ashiftrt:M <X> (const_int I)) if modes M and O are the same, and + (truncate:M (ashiftrt:O <X> (const_int I))) if M is narrower than + O, and (sign_extend:M (ashiftrt:O <X> (const_int I))) if M is + wider than O. */ + if (GET_CODE (op) == TRUNCATE + && GET_CODE (XEXP (op, 0)) == LSHIFTRT + && CONST_INT_P (XEXP (XEXP (op, 0), 1))) + { + scalar_int_mode m_mode, n_mode, o_mode; + rtx old_shift = XEXP (op, 0); + if (is_a <scalar_int_mode> (mode, &m_mode) + && is_a <scalar_int_mode> (GET_MODE (op), &n_mode) + && is_a <scalar_int_mode> (GET_MODE (old_shift), &o_mode) + && GET_MODE_PRECISION (o_mode) - GET_MODE_PRECISION (n_mode) + == INTVAL (XEXP (old_shift, 1))) + { + rtx new_shift = simplify_gen_binary (ASHIFTRT, + GET_MODE (old_shift), + XEXP (old_shift, 0), + XEXP (old_shift, 1)); + if (GET_MODE_PRECISION (m_mode) > GET_MODE_PRECISION (o_mode)) + return simplify_gen_unary (SIGN_EXTEND, mode, new_shift, + GET_MODE (new_shift)); + if (mode != GET_MODE (new_shift)) + return simplify_gen_unary (TRUNCATE, mode, new_shift, + GET_MODE (new_shift)); + return new_shift; + } + } + #if defined(POINTERS_EXTEND_UNSIGNED) /* As we do not know which address space the pointer is referring to, we can do this only if the target does not support different pointer |