/* Perform simple optimizations to clean up the result of reload.
- Copyright (C) 1987-2018 Free Software Foundation, Inc.
+ Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GCC.
for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
{
rtx part = XVECEXP (body, 0, i);
+ /* asms can only have full clobbers, not clobber_highs. */
+ gcc_assert (GET_CODE (part) != CLOBBER_HIGH);
if (GET_CODE (part) == CLOBBER && REG_P (XEXP (part, 0)))
cselib_invalidate_rtx (XEXP (part, 0));
}
}
}
else if (GET_CODE (part) != CLOBBER
+ && GET_CODE (part) != CLOBBER_HIGH
&& GET_CODE (part) != USE)
break;
}
STORE_RUID is always meaningful if we only want to use a value in a
register in a different place: it denotes the next insn in the insn
stream (i.e. the last encountered) that sets or clobbers the register.
- REAL_STORE_RUID is similar, but clobbers are ignored when updating it. */
+ REAL_STORE_RUID is similar, but clobbers are ignored when updating it.
+ EXPR is the expression used when storing the register. */
static struct
{
struct reg_use reg_use[RELOAD_COMBINE_MAX_USES];
int real_store_ruid;
int use_ruid;
bool all_offsets_match;
+ rtx expr;
} reg_state[FIRST_PSEUDO_REGISTER];
/* Reverse linear uid. This is increased in reload_combine while scanning
value in PREV, the constant loading instruction. */
validate_change (prev, &SET_DEST (prev_set), index_reg, 1);
if (reg_state[regno].offset != const0_rtx)
- validate_change (prev,
- &SET_SRC (prev_set),
- GEN_INT (INTVAL (SET_SRC (prev_set))
- + INTVAL (reg_state[regno].offset)),
- 1);
+ {
+ HOST_WIDE_INT c
+ = trunc_int_for_mode (UINTVAL (SET_SRC (prev_set))
+ + UINTVAL (reg_state[regno].offset),
+ GET_MODE (index_reg));
+ validate_change (prev, &SET_SRC (prev_set), GEN_INT (c), 1);
+ }
/* Now for every use of REG that we have recorded, replace REG
with REG_SUM. */
{
rtx setuse = XEXP (link, 0);
rtx usage_rtx = XEXP (setuse, 0);
+ /* We could support CLOBBER_HIGH and treat it in the same way as
+ HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet. */
+ gcc_assert (GET_CODE (setuse) != CLOBBER_HIGH);
+
if ((GET_CODE (setuse) == USE || GET_CODE (setuse) == CLOBBER)
&& REG_P (usage_rtx))
{
}
break;
+ case CLOBBER_HIGH:
+ gcc_assert (REG_P (SET_DEST (x)));
+ return;
+
case PLUS:
/* We are interested in (plus (reg) (const_int)) . */
if (!REG_P (XEXP (x, 0))
{
rtx setuse = XEXP (link, 0);
rtx usage_rtx = XEXP (setuse, 0);
+ /* CALL_INSN_FUNCTION_USAGEs can only have full clobbers, not
+ clobber_highs. */
+ gcc_assert (GET_CODE (setuse) != CLOBBER_HIGH);
if (GET_CODE (setuse) == CLOBBER
&& REG_P (usage_rtx))
{
move2add_record_mode (dst);
}
+ else if (GET_CODE (set) == CLOBBER_HIGH)
+ {
+ /* Only invalidate if actually clobbered. */
+ if (reg_mode[regno] == BLKmode
+ || reg_is_clobbered_by_clobber_high (regno, reg_mode[regno], dst))
+ goto invalidate;
+ }
else
{
invalidate: