machmode.h (GET_MODE_UNIT_PRECISION): New macro.
gcc/ * machmode.h (GET_MODE_UNIT_PRECISION): New macro. * simplify-rtx.c (simplify_truncation): New function, extracted from simplify_subreg and (in small part) from simplify_unary_operation_1. (simplify_unary_operation_1) <TRUNCATE>: Use it. Remove sign bit test for !TRULY_NOOP_TRUNCATION_MODES_P. (simplify_subreg): Use simplify_truncate for lowpart subregs where both the inner and outer modes are scalar integers. * config/mips/mips.c (mips_truncated_op_cost): New function. (mips_rtx_costs): Adjust test for BADDU. * config/mips/mips.md (*baddu_di<mode>): Push truncates to operands. From-SVN: r192186
This commit is contained in:
parent
ed901e4c61
commit
40c5ed5b5a
|
@ -1,3 +1,17 @@
|
||||||
|
2012-10-07 Richard Sandiford <rdsandiford@googlemail.com>
|
||||||
|
|
||||||
|
* machmode.h (GET_MODE_UNIT_PRECISION): New macro.
|
||||||
|
* simplify-rtx.c (simplify_truncation): New function,
|
||||||
|
extracted from simplify_subreg and (in small part) from
|
||||||
|
simplify_unary_operation_1.
|
||||||
|
(simplify_unary_operation_1) <TRUNCATE>: Use it. Remove sign bit
|
||||||
|
test for !TRULY_NOOP_TRUNCATION_MODES_P.
|
||||||
|
(simplify_subreg): Use simplify_truncate for lowpart subregs
|
||||||
|
where both the inner and outer modes are scalar integers.
|
||||||
|
* config/mips/mips.c (mips_truncated_op_cost): New function.
|
||||||
|
(mips_rtx_costs): Adjust test for BADDU.
|
||||||
|
* config/mips/mips.md (*baddu_di<mode>): Push truncates to operands.
|
||||||
|
|
||||||
2012-10-07 Jan Hubicka <jh@suse.cz>
|
2012-10-07 Jan Hubicka <jh@suse.cz>
|
||||||
|
|
||||||
* ipa-inline-analysis.c (do_estimate_edge_time): Return actual
|
* ipa-inline-analysis.c (do_estimate_edge_time): Return actual
|
||||||
|
|
|
@ -3557,6 +3557,17 @@ mips_set_reg_reg_cost (enum machine_mode mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the cost of an operand X that can be trucated for free.
|
||||||
|
SPEED says whether we're optimizing for size or speed. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
mips_truncated_op_cost (rtx x, bool speed)
|
||||||
|
{
|
||||||
|
if (GET_CODE (x) == TRUNCATE)
|
||||||
|
x = XEXP (x, 0);
|
||||||
|
return set_src_cost (x, speed);
|
||||||
|
}
|
||||||
|
|
||||||
/* Implement TARGET_RTX_COSTS. */
|
/* Implement TARGET_RTX_COSTS. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -3937,12 +3948,13 @@ mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
|
||||||
case ZERO_EXTEND:
|
case ZERO_EXTEND:
|
||||||
if (outer_code == SET
|
if (outer_code == SET
|
||||||
&& ISA_HAS_BADDU
|
&& ISA_HAS_BADDU
|
||||||
&& (GET_CODE (XEXP (x, 0)) == TRUNCATE
|
|
||||||
|| GET_CODE (XEXP (x, 0)) == SUBREG)
|
|
||||||
&& GET_MODE (XEXP (x, 0)) == QImode
|
&& GET_MODE (XEXP (x, 0)) == QImode
|
||||||
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS)
|
&& GET_CODE (XEXP (x, 0)) == PLUS)
|
||||||
{
|
{
|
||||||
*total = set_src_cost (XEXP (XEXP (x, 0), 0), speed);
|
rtx plus = XEXP (x, 0);
|
||||||
|
*total = (COSTS_N_INSNS (1)
|
||||||
|
+ mips_truncated_op_cost (XEXP (plus, 0), speed)
|
||||||
|
+ mips_truncated_op_cost (XEXP (plus, 1), speed));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*total = mips_zero_extend_cost (mode, XEXP (x, 0));
|
*total = mips_zero_extend_cost (mode, XEXP (x, 0));
|
||||||
|
|
|
@ -1306,9 +1306,8 @@
|
||||||
(define_insn "*baddu_di<mode>"
|
(define_insn "*baddu_di<mode>"
|
||||||
[(set (match_operand:GPR 0 "register_operand" "=d")
|
[(set (match_operand:GPR 0 "register_operand" "=d")
|
||||||
(zero_extend:GPR
|
(zero_extend:GPR
|
||||||
(truncate:QI
|
(plus:QI (truncate:QI (match_operand:DI 1 "register_operand" "d"))
|
||||||
(plus:DI (match_operand:DI 1 "register_operand" "d")
|
(truncate:QI (match_operand:DI 2 "register_operand" "d")))))]
|
||||||
(match_operand:DI 2 "register_operand" "d")))))]
|
|
||||||
"ISA_HAS_BADDU && TARGET_64BIT"
|
"ISA_HAS_BADDU && TARGET_64BIT"
|
||||||
"baddu\\t%0,%1,%2"
|
"baddu\\t%0,%1,%2"
|
||||||
[(set_attr "alu_type" "add")])
|
[(set_attr "alu_type" "add")])
|
||||||
|
|
|
@ -217,6 +217,11 @@ extern const unsigned char mode_inner[NUM_MACHINE_MODES];
|
||||||
#define GET_MODE_UNIT_BITSIZE(MODE) \
|
#define GET_MODE_UNIT_BITSIZE(MODE) \
|
||||||
((unsigned short) (GET_MODE_UNIT_SIZE (MODE) * BITS_PER_UNIT))
|
((unsigned short) (GET_MODE_UNIT_SIZE (MODE) * BITS_PER_UNIT))
|
||||||
|
|
||||||
|
#define GET_MODE_UNIT_PRECISION(MODE) \
|
||||||
|
(GET_MODE_INNER (MODE) == VOIDmode \
|
||||||
|
? GET_MODE_PRECISION (MODE) \
|
||||||
|
: GET_MODE_PRECISION (GET_MODE_INNER (MODE)))
|
||||||
|
|
||||||
/* Get the number of units in the object. */
|
/* Get the number of units in the object. */
|
||||||
|
|
||||||
extern const unsigned char mode_nunits[NUM_MACHINE_MODES];
|
extern const unsigned char mode_nunits[NUM_MACHINE_MODES];
|
||||||
|
|
|
@ -564,6 +564,212 @@ simplify_replace_rtx (rtx x, const_rtx old_rtx, rtx new_rtx)
|
||||||
return simplify_replace_fn_rtx (x, old_rtx, 0, new_rtx);
|
return simplify_replace_fn_rtx (x, old_rtx, 0, new_rtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try to simplify a MODE truncation of OP, which has OP_MODE.
|
||||||
|
Only handle cases where the truncated value is inherently an rvalue.
|
||||||
|
|
||||||
|
RTL provides two ways of truncating a value:
|
||||||
|
|
||||||
|
1. a lowpart subreg. This form is only a truncation when both
|
||||||
|
the outer and inner modes (here MODE and OP_MODE respectively)
|
||||||
|
are scalar integers, and only then when the subreg is used as
|
||||||
|
an rvalue.
|
||||||
|
|
||||||
|
It is only valid to form such truncating subregs if the
|
||||||
|
truncation requires no action by the target. The onus for
|
||||||
|
proving this is on the creator of the subreg -- e.g. the
|
||||||
|
caller to simplify_subreg or simplify_gen_subreg -- and typically
|
||||||
|
involves either TRULY_NOOP_TRUNCATION_MODES_P or truncated_to_mode.
|
||||||
|
|
||||||
|
2. a TRUNCATE. This form handles both scalar and compound integers.
|
||||||
|
|
||||||
|
The first form is preferred where valid. However, the TRUNCATE
|
||||||
|
handling in simplify_unary_operation turns the second form into the
|
||||||
|
first form when TRULY_NOOP_TRUNCATION_MODES_P or truncated_to_mode allow,
|
||||||
|
so it is generally safe to form rvalue truncations using:
|
||||||
|
|
||||||
|
simplify_gen_unary (TRUNCATE, ...)
|
||||||
|
|
||||||
|
and leave simplify_unary_operation to work out which representation
|
||||||
|
should be used.
|
||||||
|
|
||||||
|
Because of the proof requirements on (1), simplify_truncation must
|
||||||
|
also use simplify_gen_unary (TRUNCATE, ...) to truncate parts of OP,
|
||||||
|
regardless of whether the outer truncation came from a SUBREG or a
|
||||||
|
TRUNCATE. For example, if the caller has proven that an SImode
|
||||||
|
truncation of:
|
||||||
|
|
||||||
|
(and:DI X Y)
|
||||||
|
|
||||||
|
is a no-op and can be represented as a subreg, it does not follow
|
||||||
|
that SImode truncations of X and Y are also no-ops. On a target
|
||||||
|
like 64-bit MIPS that requires SImode values to be stored in
|
||||||
|
sign-extended form, an SImode truncation of:
|
||||||
|
|
||||||
|
(and:DI (reg:DI X) (const_int 63))
|
||||||
|
|
||||||
|
is trivially a no-op because only the lower 6 bits can be set.
|
||||||
|
However, X is still an arbitrary 64-bit number and so we cannot
|
||||||
|
assume that truncating it too is a no-op. */
|
||||||
|
|
||||||
|
static rtx
|
||||||
|
simplify_truncation (enum machine_mode mode, rtx op,
|
||||||
|
enum machine_mode op_mode)
|
||||||
|
{
|
||||||
|
unsigned int precision = GET_MODE_UNIT_PRECISION (mode);
|
||||||
|
unsigned int op_precision = GET_MODE_UNIT_PRECISION (op_mode);
|
||||||
|
gcc_assert (precision <= op_precision);
|
||||||
|
|
||||||
|
/* Optimize truncations of zero and sign extended values. */
|
||||||
|
if (GET_CODE (op) == ZERO_EXTEND
|
||||||
|
|| GET_CODE (op) == SIGN_EXTEND)
|
||||||
|
{
|
||||||
|
/* There are three possibilities. If MODE is the same as the
|
||||||
|
origmode, we can omit both the extension and the subreg.
|
||||||
|
If MODE is not larger than the origmode, we can apply the
|
||||||
|
truncation without the extension. Finally, if the outermode
|
||||||
|
is larger than the origmode, we can just extend to the appropriate
|
||||||
|
mode. */
|
||||||
|
enum machine_mode origmode = GET_MODE (XEXP (op, 0));
|
||||||
|
if (mode == origmode)
|
||||||
|
return XEXP (op, 0);
|
||||||
|
else if (precision <= GET_MODE_UNIT_PRECISION (origmode))
|
||||||
|
return simplify_gen_unary (TRUNCATE, mode,
|
||||||
|
XEXP (op, 0), origmode);
|
||||||
|
else
|
||||||
|
return simplify_gen_unary (GET_CODE (op), mode,
|
||||||
|
XEXP (op, 0), origmode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simplify (truncate:SI (op:DI (x:DI) (y:DI)))
|
||||||
|
to (op:SI (truncate:SI (x:DI)) (truncate:SI (x:DI))). */
|
||||||
|
if (GET_CODE (op) == PLUS
|
||||||
|
|| GET_CODE (op) == MINUS
|
||||||
|
|| GET_CODE (op) == MULT)
|
||||||
|
{
|
||||||
|
rtx op0 = simplify_gen_unary (TRUNCATE, mode, XEXP (op, 0), op_mode);
|
||||||
|
if (op0)
|
||||||
|
{
|
||||||
|
rtx op1 = simplify_gen_unary (TRUNCATE, mode, XEXP (op, 1), op_mode);
|
||||||
|
if (op1)
|
||||||
|
return simplify_gen_binary (GET_CODE (op), mode, op0, op1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simplify (truncate:QI (lshiftrt:SI (sign_extend:SI (x:QI)) C)) into
|
||||||
|
to (ashiftrt:QI (x:QI) C), where C is a suitable small constant and
|
||||||
|
the outer subreg is effectively a truncation to the original mode. */
|
||||||
|
if ((GET_CODE (op) == LSHIFTRT
|
||||||
|
|| GET_CODE (op) == ASHIFTRT)
|
||||||
|
/* Ensure that OP_MODE is at least twice as wide as MODE
|
||||||
|
to avoid the possibility that an outer LSHIFTRT shifts by more
|
||||||
|
than the sign extension's sign_bit_copies and introduces zeros
|
||||||
|
into the high bits of the result. */
|
||||||
|
&& 2 * precision <= op_precision
|
||||||
|
&& CONST_INT_P (XEXP (op, 1))
|
||||||
|
&& GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
|
||||||
|
&& GET_MODE (XEXP (XEXP (op, 0), 0)) == mode
|
||||||
|
&& INTVAL (XEXP (op, 1)) < precision)
|
||||||
|
return simplify_gen_binary (ASHIFTRT, mode,
|
||||||
|
XEXP (XEXP (op, 0), 0), XEXP (op, 1));
|
||||||
|
|
||||||
|
/* Likewise (truncate:QI (lshiftrt:SI (zero_extend:SI (x:QI)) C)) into
|
||||||
|
to (lshiftrt:QI (x:QI) C), where C is a suitable small constant and
|
||||||
|
the outer subreg is effectively a truncation to the original mode. */
|
||||||
|
if ((GET_CODE (op) == LSHIFTRT
|
||||||
|
|| GET_CODE (op) == ASHIFTRT)
|
||||||
|
&& CONST_INT_P (XEXP (op, 1))
|
||||||
|
&& GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
|
||||||
|
&& GET_MODE (XEXP (XEXP (op, 0), 0)) == mode
|
||||||
|
&& INTVAL (XEXP (op, 1)) < precision)
|
||||||
|
return simplify_gen_binary (LSHIFTRT, mode,
|
||||||
|
XEXP (XEXP (op, 0), 0), XEXP (op, 1));
|
||||||
|
|
||||||
|
/* Likewise (truncate:QI (ashift:SI (zero_extend:SI (x:QI)) C)) into
|
||||||
|
to (ashift:QI (x:QI) C), where C is a suitable small constant and
|
||||||
|
the outer subreg is effectively a truncation to the original mode. */
|
||||||
|
if (GET_CODE (op) == ASHIFT
|
||||||
|
&& CONST_INT_P (XEXP (op, 1))
|
||||||
|
&& (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
|
||||||
|
|| GET_CODE (XEXP (op, 0)) == SIGN_EXTEND)
|
||||||
|
&& GET_MODE (XEXP (XEXP (op, 0), 0)) == mode
|
||||||
|
&& INTVAL (XEXP (op, 1)) < precision)
|
||||||
|
return simplify_gen_binary (ASHIFT, mode,
|
||||||
|
XEXP (XEXP (op, 0), 0), XEXP (op, 1));
|
||||||
|
|
||||||
|
/* Recognize a word extraction from a multi-word subreg. */
|
||||||
|
if ((GET_CODE (op) == LSHIFTRT
|
||||||
|
|| GET_CODE (op) == ASHIFTRT)
|
||||||
|
&& SCALAR_INT_MODE_P (mode)
|
||||||
|
&& SCALAR_INT_MODE_P (op_mode)
|
||||||
|
&& precision >= BITS_PER_WORD
|
||||||
|
&& 2 * precision <= op_precision
|
||||||
|
&& CONST_INT_P (XEXP (op, 1))
|
||||||
|
&& (INTVAL (XEXP (op, 1)) & (precision - 1)) == 0
|
||||||
|
&& INTVAL (XEXP (op, 1)) >= 0
|
||||||
|
&& INTVAL (XEXP (op, 1)) < op_precision)
|
||||||
|
{
|
||||||
|
int byte = subreg_lowpart_offset (mode, op_mode);
|
||||||
|
int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT;
|
||||||
|
return simplify_gen_subreg (mode, XEXP (op, 0), op_mode,
|
||||||
|
(WORDS_BIG_ENDIAN
|
||||||
|
? byte - shifted_bytes
|
||||||
|
: byte + shifted_bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a TRUNCATE of a right shift of MEM, make a new MEM
|
||||||
|
and try replacing the TRUNCATE and shift with it. Don't do this
|
||||||
|
if the MEM has a mode-dependent address. */
|
||||||
|
if ((GET_CODE (op) == LSHIFTRT
|
||||||
|
|| GET_CODE (op) == ASHIFTRT)
|
||||||
|
&& SCALAR_INT_MODE_P (op_mode)
|
||||||
|
&& MEM_P (XEXP (op, 0))
|
||||||
|
&& CONST_INT_P (XEXP (op, 1))
|
||||||
|
&& (INTVAL (XEXP (op, 1)) % GET_MODE_BITSIZE (mode)) == 0
|
||||||
|
&& INTVAL (XEXP (op, 1)) > 0
|
||||||
|
&& INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (op_mode)
|
||||||
|
&& ! mode_dependent_address_p (XEXP (XEXP (op, 0), 0),
|
||||||
|
MEM_ADDR_SPACE (XEXP (op, 0)))
|
||||||
|
&& ! MEM_VOLATILE_P (XEXP (op, 0))
|
||||||
|
&& (GET_MODE_SIZE (mode) >= UNITS_PER_WORD
|
||||||
|
|| WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN))
|
||||||
|
{
|
||||||
|
int byte = subreg_lowpart_offset (mode, op_mode);
|
||||||
|
int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT;
|
||||||
|
return adjust_address_nv (XEXP (op, 0), mode,
|
||||||
|
(WORDS_BIG_ENDIAN
|
||||||
|
? byte - shifted_bytes
|
||||||
|
: byte + shifted_bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
|
||||||
|
(OP:SI foo:SI) if OP is NEG or ABS. */
|
||||||
|
if ((GET_CODE (op) == ABS
|
||||||
|
|| GET_CODE (op) == NEG)
|
||||||
|
&& (GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
|
||||||
|
|| GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
|
||||||
|
&& GET_MODE (XEXP (XEXP (op, 0), 0)) == mode)
|
||||||
|
return simplify_gen_unary (GET_CODE (op), mode,
|
||||||
|
XEXP (XEXP (op, 0), 0), mode);
|
||||||
|
|
||||||
|
/* (truncate:A (subreg:B (truncate:C X) 0)) is
|
||||||
|
(truncate:A X). */
|
||||||
|
if (GET_CODE (op) == SUBREG
|
||||||
|
&& SCALAR_INT_MODE_P (mode)
|
||||||
|
&& SCALAR_INT_MODE_P (op_mode)
|
||||||
|
&& SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (op)))
|
||||||
|
&& GET_CODE (SUBREG_REG (op)) == TRUNCATE
|
||||||
|
&& subreg_lowpart_p (op))
|
||||||
|
return simplify_gen_unary (TRUNCATE, mode, XEXP (SUBREG_REG (op), 0),
|
||||||
|
GET_MODE (XEXP (SUBREG_REG (op), 0)));
|
||||||
|
|
||||||
|
/* (truncate:A (truncate:B X)) is (truncate:A X). */
|
||||||
|
if (GET_CODE (op) == TRUNCATE)
|
||||||
|
return simplify_gen_unary (TRUNCATE, mode, XEXP (op, 0),
|
||||||
|
GET_MODE (XEXP (op, 0)));
|
||||||
|
|
||||||
|
return NULL_RTX;
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to simplify a unary operation CODE whose output mode is to be
|
/* Try to simplify a unary operation CODE whose output mode is to be
|
||||||
MODE with input operand OP whose mode was originally OP_MODE.
|
MODE with input operand OP whose mode was originally OP_MODE.
|
||||||
Return zero if no simplification can be made. */
|
Return zero if no simplification can be made. */
|
||||||
|
@ -815,50 +1021,34 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRUNCATE:
|
case TRUNCATE:
|
||||||
/* We can't handle truncation to a partial integer mode here
|
/* Don't optimize (lshiftrt (mult ...)) as it would interfere
|
||||||
because we don't know the real bitsize of the partial
|
with the umulXi3_highpart patterns. */
|
||||||
integer mode. */
|
if (GET_CODE (op) == LSHIFTRT
|
||||||
|
&& GET_CODE (XEXP (op, 0)) == MULT)
|
||||||
|
break;
|
||||||
|
|
||||||
if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
|
if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
|
||||||
break;
|
{
|
||||||
|
if (TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (op)))
|
||||||
|
return rtl_hooks.gen_lowpart_no_emit (mode, op);
|
||||||
|
/* We can't handle truncation to a partial integer mode here
|
||||||
|
because we don't know the real bitsize of the partial
|
||||||
|
integer mode. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI. */
|
if (GET_MODE (op) != VOIDmode)
|
||||||
if ((GET_CODE (op) == SIGN_EXTEND
|
{
|
||||||
|| GET_CODE (op) == ZERO_EXTEND)
|
temp = simplify_truncation (mode, op, GET_MODE (op));
|
||||||
&& GET_MODE (XEXP (op, 0)) == mode)
|
if (temp)
|
||||||
return XEXP (op, 0);
|
return temp;
|
||||||
|
}
|
||||||
/* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
|
|
||||||
(OP:SI foo:SI) if OP is NEG or ABS. */
|
|
||||||
if ((GET_CODE (op) == ABS
|
|
||||||
|| GET_CODE (op) == NEG)
|
|
||||||
&& (GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
|
|
||||||
|| GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
|
|
||||||
&& GET_MODE (XEXP (XEXP (op, 0), 0)) == mode)
|
|
||||||
return simplify_gen_unary (GET_CODE (op), mode,
|
|
||||||
XEXP (XEXP (op, 0), 0), mode);
|
|
||||||
|
|
||||||
/* (truncate:A (subreg:B (truncate:C X) 0)) is
|
|
||||||
(truncate:A X). */
|
|
||||||
if (GET_CODE (op) == SUBREG
|
|
||||||
&& GET_CODE (SUBREG_REG (op)) == TRUNCATE
|
|
||||||
&& subreg_lowpart_p (op))
|
|
||||||
return simplify_gen_unary (TRUNCATE, mode, XEXP (SUBREG_REG (op), 0),
|
|
||||||
GET_MODE (XEXP (SUBREG_REG (op), 0)));
|
|
||||||
|
|
||||||
/* If we know that the value is already truncated, we can
|
/* If we know that the value is already truncated, we can
|
||||||
replace the TRUNCATE with a SUBREG. Note that this is also
|
replace the TRUNCATE with a SUBREG. */
|
||||||
valid if TRULY_NOOP_TRUNCATION is false for the corresponding
|
if (GET_MODE_NUNITS (mode) == 1
|
||||||
modes we just have to apply a different definition for
|
&& (TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (op))
|
||||||
truncation. But don't do this for an (LSHIFTRT (MULT ...))
|
|| truncated_to_mode (mode, op)))
|
||||||
since this will cause problems with the umulXi3_highpart
|
|
||||||
patterns. */
|
|
||||||
if ((TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (op))
|
|
||||||
? (num_sign_bit_copies (op, GET_MODE (op))
|
|
||||||
> (unsigned int) (GET_MODE_PRECISION (GET_MODE (op))
|
|
||||||
- GET_MODE_PRECISION (mode)))
|
|
||||||
: truncated_to_mode (mode, op))
|
|
||||||
&& ! (GET_CODE (op) == LSHIFTRT
|
|
||||||
&& GET_CODE (XEXP (op, 0)) == MULT))
|
|
||||||
return rtl_hooks.gen_lowpart_no_emit (mode, op);
|
return rtl_hooks.gen_lowpart_no_emit (mode, op);
|
||||||
|
|
||||||
/* A truncate of a comparison can be replaced with a subreg if
|
/* A truncate of a comparison can be replaced with a subreg if
|
||||||
|
@ -5596,14 +5786,6 @@ simplify_subreg (enum machine_mode outermode, rtx op,
|
||||||
return NULL_RTX;
|
return NULL_RTX;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Merge implicit and explicit truncations. */
|
|
||||||
|
|
||||||
if (GET_CODE (op) == TRUNCATE
|
|
||||||
&& GET_MODE_SIZE (outermode) < GET_MODE_SIZE (innermode)
|
|
||||||
&& subreg_lowpart_offset (outermode, innermode) == byte)
|
|
||||||
return simplify_gen_unary (TRUNCATE, outermode, XEXP (op, 0),
|
|
||||||
GET_MODE (XEXP (op, 0)));
|
|
||||||
|
|
||||||
/* SUBREG of a hard register => just change the register number
|
/* SUBREG of a hard register => just change the register number
|
||||||
and/or mode. If the hard register is not valid in that mode,
|
and/or mode. If the hard register is not valid in that mode,
|
||||||
suppress this simplification. If the hard register is the stack,
|
suppress this simplification. If the hard register is the stack,
|
||||||
|
@ -5689,160 +5871,23 @@ simplify_subreg (enum machine_mode outermode, rtx op,
|
||||||
return NULL_RTX;
|
return NULL_RTX;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optimize SUBREG truncations of zero and sign extended values. */
|
/* A SUBREG resulting from a zero extension may fold to zero if
|
||||||
if ((GET_CODE (op) == ZERO_EXTEND
|
it extracts higher bits that the ZERO_EXTEND's source bits. */
|
||||||
|| GET_CODE (op) == SIGN_EXTEND)
|
if (GET_CODE (op) == ZERO_EXTEND)
|
||||||
&& SCALAR_INT_MODE_P (innermode)
|
|
||||||
&& GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode))
|
|
||||||
{
|
{
|
||||||
unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
|
unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
|
||||||
|
if (bitpos >= GET_MODE_PRECISION (GET_MODE (XEXP (op, 0))))
|
||||||
/* If we're requesting the lowpart of a zero or sign extension,
|
|
||||||
there are three possibilities. If the outermode is the same
|
|
||||||
as the origmode, we can omit both the extension and the subreg.
|
|
||||||
If the outermode is not larger than the origmode, we can apply
|
|
||||||
the truncation without the extension. Finally, if the outermode
|
|
||||||
is larger than the origmode, but both are integer modes, we
|
|
||||||
can just extend to the appropriate mode. */
|
|
||||||
if (bitpos == 0)
|
|
||||||
{
|
|
||||||
enum machine_mode origmode = GET_MODE (XEXP (op, 0));
|
|
||||||
if (outermode == origmode)
|
|
||||||
return XEXP (op, 0);
|
|
||||||
if (GET_MODE_PRECISION (outermode) <= GET_MODE_PRECISION (origmode))
|
|
||||||
return simplify_gen_subreg (outermode, XEXP (op, 0), origmode,
|
|
||||||
subreg_lowpart_offset (outermode,
|
|
||||||
origmode));
|
|
||||||
if (SCALAR_INT_MODE_P (outermode))
|
|
||||||
return simplify_gen_unary (GET_CODE (op), outermode,
|
|
||||||
XEXP (op, 0), origmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A SUBREG resulting from a zero extension may fold to zero if
|
|
||||||
it extracts higher bits that the ZERO_EXTEND's source bits. */
|
|
||||||
if (GET_CODE (op) == ZERO_EXTEND
|
|
||||||
&& bitpos >= GET_MODE_PRECISION (GET_MODE (XEXP (op, 0))))
|
|
||||||
return CONST0_RTX (outermode);
|
return CONST0_RTX (outermode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simplify (subreg:SI (op:DI ((x:DI) (y:DI)), 0)
|
if (SCALAR_INT_MODE_P (outermode)
|
||||||
to (op:SI (subreg:SI (x:DI) 0) (subreg:SI (x:DI) 0)), where
|
|
||||||
the outer subreg is effectively a truncation to the original mode. */
|
|
||||||
if ((GET_CODE (op) == PLUS
|
|
||||||
|| GET_CODE (op) == MINUS
|
|
||||||
|| GET_CODE (op) == MULT)
|
|
||||||
&& SCALAR_INT_MODE_P (outermode)
|
|
||||||
&& SCALAR_INT_MODE_P (innermode)
|
&& SCALAR_INT_MODE_P (innermode)
|
||||||
&& GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode)
|
&& GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode)
|
||||||
&& byte == subreg_lowpart_offset (outermode, innermode))
|
&& byte == subreg_lowpart_offset (outermode, innermode))
|
||||||
{
|
{
|
||||||
rtx op0 = simplify_gen_subreg (outermode, XEXP (op, 0),
|
rtx tem = simplify_truncation (outermode, op, innermode);
|
||||||
innermode, byte);
|
if (tem)
|
||||||
if (op0)
|
return tem;
|
||||||
{
|
|
||||||
rtx op1 = simplify_gen_subreg (outermode, XEXP (op, 1),
|
|
||||||
innermode, byte);
|
|
||||||
if (op1)
|
|
||||||
return simplify_gen_binary (GET_CODE (op), outermode, op0, op1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Simplify (subreg:QI (lshiftrt:SI (sign_extend:SI (x:QI)) C), 0) into
|
|
||||||
to (ashiftrt:QI (x:QI) C), where C is a suitable small constant and
|
|
||||||
the outer subreg is effectively a truncation to the original mode. */
|
|
||||||
if ((GET_CODE (op) == LSHIFTRT
|
|
||||||
|| GET_CODE (op) == ASHIFTRT)
|
|
||||||
&& SCALAR_INT_MODE_P (outermode)
|
|
||||||
&& SCALAR_INT_MODE_P (innermode)
|
|
||||||
/* Ensure that OUTERMODE is at least twice as wide as the INNERMODE
|
|
||||||
to avoid the possibility that an outer LSHIFTRT shifts by more
|
|
||||||
than the sign extension's sign_bit_copies and introduces zeros
|
|
||||||
into the high bits of the result. */
|
|
||||||
&& (2 * GET_MODE_PRECISION (outermode)) <= GET_MODE_PRECISION (innermode)
|
|
||||||
&& CONST_INT_P (XEXP (op, 1))
|
|
||||||
&& GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
|
|
||||||
&& GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
|
|
||||||
&& INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (outermode)
|
|
||||||
&& subreg_lsb_1 (outermode, innermode, byte) == 0)
|
|
||||||
return simplify_gen_binary (ASHIFTRT, outermode,
|
|
||||||
XEXP (XEXP (op, 0), 0), XEXP (op, 1));
|
|
||||||
|
|
||||||
/* Likewise (subreg:QI (lshiftrt:SI (zero_extend:SI (x:QI)) C), 0) into
|
|
||||||
to (lshiftrt:QI (x:QI) C), where C is a suitable small constant and
|
|
||||||
the outer subreg is effectively a truncation to the original mode. */
|
|
||||||
if ((GET_CODE (op) == LSHIFTRT
|
|
||||||
|| GET_CODE (op) == ASHIFTRT)
|
|
||||||
&& SCALAR_INT_MODE_P (outermode)
|
|
||||||
&& SCALAR_INT_MODE_P (innermode)
|
|
||||||
&& GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode)
|
|
||||||
&& CONST_INT_P (XEXP (op, 1))
|
|
||||||
&& GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
|
|
||||||
&& GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
|
|
||||||
&& INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (outermode)
|
|
||||||
&& subreg_lsb_1 (outermode, innermode, byte) == 0)
|
|
||||||
return simplify_gen_binary (LSHIFTRT, outermode,
|
|
||||||
XEXP (XEXP (op, 0), 0), XEXP (op, 1));
|
|
||||||
|
|
||||||
/* Likewise (subreg:QI (ashift:SI (zero_extend:SI (x:QI)) C), 0) into
|
|
||||||
to (ashift:QI (x:QI) C), where C is a suitable small constant and
|
|
||||||
the outer subreg is effectively a truncation to the original mode. */
|
|
||||||
if (GET_CODE (op) == ASHIFT
|
|
||||||
&& SCALAR_INT_MODE_P (outermode)
|
|
||||||
&& SCALAR_INT_MODE_P (innermode)
|
|
||||||
&& GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode)
|
|
||||||
&& CONST_INT_P (XEXP (op, 1))
|
|
||||||
&& (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
|
|
||||||
|| GET_CODE (XEXP (op, 0)) == SIGN_EXTEND)
|
|
||||||
&& GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
|
|
||||||
&& INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (outermode)
|
|
||||||
&& subreg_lsb_1 (outermode, innermode, byte) == 0)
|
|
||||||
return simplify_gen_binary (ASHIFT, outermode,
|
|
||||||
XEXP (XEXP (op, 0), 0), XEXP (op, 1));
|
|
||||||
|
|
||||||
/* Recognize a word extraction from a multi-word subreg. */
|
|
||||||
if ((GET_CODE (op) == LSHIFTRT
|
|
||||||
|| GET_CODE (op) == ASHIFTRT)
|
|
||||||
&& SCALAR_INT_MODE_P (innermode)
|
|
||||||
&& GET_MODE_PRECISION (outermode) >= BITS_PER_WORD
|
|
||||||
&& GET_MODE_PRECISION (innermode) >= (2 * GET_MODE_PRECISION (outermode))
|
|
||||||
&& CONST_INT_P (XEXP (op, 1))
|
|
||||||
&& (INTVAL (XEXP (op, 1)) & (GET_MODE_PRECISION (outermode) - 1)) == 0
|
|
||||||
&& INTVAL (XEXP (op, 1)) >= 0
|
|
||||||
&& INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (innermode)
|
|
||||||
&& byte == subreg_lowpart_offset (outermode, innermode))
|
|
||||||
{
|
|
||||||
int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT;
|
|
||||||
return simplify_gen_subreg (outermode, XEXP (op, 0), innermode,
|
|
||||||
(WORDS_BIG_ENDIAN
|
|
||||||
? byte - shifted_bytes
|
|
||||||
: byte + shifted_bytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we have a lowpart SUBREG of a right shift of MEM, make a new MEM
|
|
||||||
and try replacing the SUBREG and shift with it. Don't do this if
|
|
||||||
the MEM has a mode-dependent address or if we would be widening it. */
|
|
||||||
|
|
||||||
if ((GET_CODE (op) == LSHIFTRT
|
|
||||||
|| GET_CODE (op) == ASHIFTRT)
|
|
||||||
&& SCALAR_INT_MODE_P (innermode)
|
|
||||||
&& MEM_P (XEXP (op, 0))
|
|
||||||
&& CONST_INT_P (XEXP (op, 1))
|
|
||||||
&& GET_MODE_SIZE (outermode) < GET_MODE_SIZE (GET_MODE (op))
|
|
||||||
&& (INTVAL (XEXP (op, 1)) % GET_MODE_BITSIZE (outermode)) == 0
|
|
||||||
&& INTVAL (XEXP (op, 1)) > 0
|
|
||||||
&& INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (innermode)
|
|
||||||
&& ! mode_dependent_address_p (XEXP (XEXP (op, 0), 0),
|
|
||||||
MEM_ADDR_SPACE (XEXP (op, 0)))
|
|
||||||
&& ! MEM_VOLATILE_P (XEXP (op, 0))
|
|
||||||
&& byte == subreg_lowpart_offset (outermode, innermode)
|
|
||||||
&& (GET_MODE_SIZE (outermode) >= UNITS_PER_WORD
|
|
||||||
|| WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN))
|
|
||||||
{
|
|
||||||
int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT;
|
|
||||||
return adjust_address_nv (XEXP (op, 0), outermode,
|
|
||||||
(WORDS_BIG_ENDIAN
|
|
||||||
? byte - shifted_bytes
|
|
||||||
: byte + shifted_bytes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL_RTX;
|
return NULL_RTX;
|
||||||
|
|
Loading…
Reference in New Issue