/* Optimize by combining instructions for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
#include "expr.h"
#include "insn-attr.h"
#include "recog.h"
-#include "real.h"
#include "toplev.h"
#include "target.h"
#include "optabs.h"
static rtx try_combine (rtx, rtx, rtx, int *);
static void undo_all (void);
static void undo_commit (void);
-static rtx *find_split_point (rtx *, rtx);
+static rtx *find_split_point (rtx *, rtx, bool);
static rtx subst (rtx, rtx, rtx, int, int);
static rtx combine_simplify_rtx (rtx, enum machine_mode, int);
static rtx simplify_if_then_else (rtx);
for (arg = DECL_ARGUMENTS (current_function_decl); arg;
arg = TREE_CHAIN (arg))
{
- rtx reg = DECL_INCOMING_RTL (arg);
+ rtx x, reg = DECL_INCOMING_RTL (arg);
int uns1, uns3;
enum machine_mode mode1, mode2, mode3, mode4;
/* The mode of the register in which the argument is being passed. */
mode4 = GET_MODE (reg);
- /* Eliminate sign extensions in the callee when possible. Only
- do this when:
- (a) A mode promotion has occurred;
- (b) The mode of the register is the same as the mode of
- the argument as it is passed; and
- (c) Either there's no language level extension, or the extension
- from source to end result is valid. The later case is true
- when the signedness of the extensions match, or when the
- language level extension is unsigned. In the later case,
- a zero extension followed by a sign extension is the same
- as one big zero extension.
- (d) When no language-level promotions (which we cannot guarantee
- will have been done by an external caller) are necessary,
- unless we know that this function is only ever called from
- the current compilation unit -- all of whose call sites will
- do the mode1 --> mode2 promotion. */
- if (mode1 != mode3
- && mode3 == mode4
- && (mode1 == mode2 || ((uns1 || !uns3) && strictly_local)))
- {
- /* Record that the value was promoted from mode1 to mode3,
- so that any sign extension at the head of the current
- function may be eliminated. */
- rtx x;
- x = gen_rtx_CLOBBER (mode1, const0_rtx);
- x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
- record_value_for_reg (reg, first, x);
- }
+ /* Eliminate sign extensions in the callee when:
+ (a) A mode promotion has occurred; */
+ if (mode1 == mode3)
+ continue;
+ /* (b) The mode of the register is the same as the mode of
+ the argument as it is passed; */
+ if (mode3 != mode4)
+ continue;
+ /* (c) There's no language level extension; */
+ if (mode1 == mode2)
+ ;
+ /* (c.1) All callers are from the current compilation unit. If that's
+ the case we don't have to rely on an ABI, we only have to know
+ what we're generating right now, and we know that we will do the
+ mode1 to mode2 promotion with the given sign. */
+ else if (!strictly_local)
+ continue;
+ /* (c.2) The combination of the two promotions is useful. This is
+ true when the signs match, or if the first promotion is unsigned.
+ In the later case, (sign_extend (zero_extend x)) is the same as
+ (zero_extend (zero_extend x)), so make sure to force UNS3 true. */
+ else if (uns1)
+ uns3 = true;
+ else if (uns3)
+ continue;
+
+ /* Record that the value was promoted from mode1 to mode3,
+ so that any sign extension at the head of the current
+ function may be eliminated. */
+ x = gen_rtx_CLOBBER (mode1, const0_rtx);
+ x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
+ record_value_for_reg (reg, first, x);
}
}
unsigned regno, nregs;
/* We assume here that no machine mode needs more than
32 hard registers when the value overlaps with a register
- for which FUNCTION_VALUE_REGNO_P is true. */
+ for which TARGET_FUNCTION_VALUE_REGNO_P is true. */
unsigned mask;
struct likely_spilled_retval_info info;
if (!NONJUMP_INSN_P (use) || GET_CODE (PATTERN (use)) != USE || insn == use)
return 0;
reg = XEXP (PATTERN (use), 0);
- if (!REG_P (reg) || !FUNCTION_VALUE_REGNO_P (REGNO (reg)))
+ if (!REG_P (reg) || !targetm.calls.function_value_regno_p (REGNO (reg)))
return 0;
regno = REGNO (reg);
nregs = hard_regno_nregs[regno][GET_MODE (reg)];
substituted. */
static rtx
-propagate_for_debug_subst (rtx from ATTRIBUTE_UNUSED, void *data)
+propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
{
struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data;
+ if (!rtx_equal_p (from, old_rtx))
+ return NULL_RTX;
if (!pair->adjusted)
{
pair->adjusted = true;
propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move)
{
rtx next, move_pos = move ? last : NULL_RTX, loc;
+ bool first_p;
#ifdef AUTO_INC_DEC
struct rtx_subst_pair p;
p.after = move;
#endif
+ first_p = true;
next = NEXT_INSN (insn);
while (next != last)
{
next = NEXT_INSN (insn);
if (DEBUG_INSN_P (insn))
{
+ if (first_p)
+ {
+ src = make_compound_operation (src, SET);
+ first_p = false;
+ }
#ifdef AUTO_INC_DEC
loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
dest, propagate_for_debug_subst, &p);
i2dest = SET_DEST (temp);
i2dest_killed = dead_or_set_p (i2, i2dest);
+ /* Replace the source in I2 with the new constant and make the
+ resulting insn the new pattern for I3. Then skip to where we
+ validate the pattern. Everything was set up above. */
SUBST (SET_SRC (temp),
immed_double_const (olo, ohi, GET_MODE (SET_DEST (temp))));
newpat = PATTERN (i2);
+
+ /* The dest of I3 has been replaced with the dest of I2. */
+ changed_i3_dest = 1;
goto validate_replacement;
}
}
}
}
- /* We come here when we are replacing a destination in I2 with the
- destination of I3. */
validate_replacement:
/* Note which hard regs this insn has as inputs. */
/* If we can split it and use I2DEST, go ahead and see if that
helps things be recognized. Verify that none of the registers
are set between I2 and I3. */
- if (insn_code_number < 0 && (split = find_split_point (&newpat, i3)) != 0
+ if (insn_code_number < 0
+ && (split = find_split_point (&newpat, i3, false)) != 0
#ifdef HAVE_cc0
&& REG_P (i2dest)
#endif
i2scratch = true;
+ /* *SPLIT may be part of I2SRC, so make sure we have the
+ original expression around for later debug processing.
+ We should not need I2SRC any more in other cases. */
+ if (MAY_HAVE_DEBUG_INSNS)
+ i2src = copy_rtx (i2src);
+ else
+ i2src = NULL;
+
/* Get NEWDEST as a register in the proper mode. We have already
validated that we can do this. */
if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
call_usage = copy_rtx (call_usage);
if (substed_i2)
- replace_rtx (call_usage, i2dest, i2src);
+ {
+ /* I2SRC must still be meaningful at this point. Some splitting
+ operations can invalidate I2SRC, but those operations do not
+ apply to calls. */
+ gcc_assert (i2src);
+ replace_rtx (call_usage, i2dest, i2src);
+ }
if (substed_i1)
replace_rtx (call_usage, i1dest, i1src);
two insns. */
static rtx *
-find_split_point (rtx *loc, rtx insn)
+find_split_point (rtx *loc, rtx insn, bool set_src)
{
rtx x = *loc;
enum rtx_code code = GET_CODE (x);
if (MEM_P (SUBREG_REG (x)))
return loc;
#endif
- return find_split_point (&SUBREG_REG (x), insn);
+ return find_split_point (&SUBREG_REG (x), insn, false);
case MEM:
#ifdef HAVE_lo_sum
#endif
/* See if we can split SET_SRC as it stands. */
- split = find_split_point (&SET_SRC (x), insn);
+ split = find_split_point (&SET_SRC (x), insn, true);
if (split && split != &SET_SRC (x))
return split;
/* See if we can split SET_DEST as it stands. */
- split = find_split_point (&SET_DEST (x), insn);
+ split = find_split_point (&SET_DEST (x), insn, false);
if (split && split != &SET_DEST (x))
return split;
SUBST (SET_DEST (x), dest);
- split = find_split_point (&SET_SRC (x), insn);
+ split = find_split_point (&SET_SRC (x), insn, true);
if (split && split != &SET_SRC (x))
return split;
}
if (extraction != 0)
{
SUBST (SET_SRC (x), extraction);
- return find_split_point (loc, insn);
+ return find_split_point (loc, insn, false);
}
}
break;
XEXP (SET_SRC (x), 0),
GEN_INT (pos))));
- split = find_split_point (&SET_SRC (x), insn);
+ split = find_split_point (&SET_SRC (x), insn, true);
if (split && split != &SET_SRC (x))
return split;
}
GEN_INT (pos)),
GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
- split = find_split_point (&SET_SRC (x), insn);
+ split = find_split_point (&SET_SRC (x), insn, true);
if (split && split != &SET_SRC (x))
return split;
}
- len - pos)),
GEN_INT (GET_MODE_BITSIZE (mode) - len)));
- split = find_split_point (&SET_SRC (x), insn);
+ split = find_split_point (&SET_SRC (x), insn, true);
if (split && split != &SET_SRC (x))
return split;
}
GET_MODE (x),
XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 1), 0))));
- return find_split_point (loc, insn);
+ return find_split_point (loc, insn, set_src);
}
/* Many RISC machines have a large set of logical insns. If the
}
break;
+ case PLUS:
+ case MINUS:
+ /* Split at a multiply-accumulate instruction. However if this is
+ the SET_SRC, we likely do not have such an instruction and it's
+ worthless to try this split. */
+ if (!set_src && GET_CODE (XEXP (x, 0)) == MULT)
+ return loc;
+
default:
break;
}
{
case RTX_BITFIELD_OPS: /* This is ZERO_EXTRACT and SIGN_EXTRACT. */
case RTX_TERNARY:
- split = find_split_point (&XEXP (x, 2), insn);
+ split = find_split_point (&XEXP (x, 2), insn, false);
if (split)
return split;
/* ... fall through ... */
case RTX_COMM_ARITH:
case RTX_COMPARE:
case RTX_COMM_COMPARE:
- split = find_split_point (&XEXP (x, 1), insn);
+ split = find_split_point (&XEXP (x, 1), insn, false);
if (split)
return split;
/* ... fall through ... */
if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND)
return &XEXP (x, 0);
- split = find_split_point (&XEXP (x, 0), insn);
+ split = find_split_point (&XEXP (x, 0), insn, false);
if (split)
return split;
return loc;
if (mode == tmode)
return new_rtx;
- if (CONST_INT_P (new_rtx))
- return gen_int_mode (INTVAL (new_rtx), mode);
+ if (CONST_INT_P (new_rtx)
+ || GET_CODE (new_rtx) == CONST_DOUBLE)
+ return simplify_unary_operation (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
+ mode, new_rtx, tmode);
/* If we know that no extraneous bits are set, and that the high
bit is not set, convert the extraction to the cheaper of
tem = make_compound_operation (SUBREG_REG (x), in_code);
{
- rtx simplified;
- simplified = simplify_subreg (GET_MODE (x), tem, GET_MODE (tem),
- SUBREG_BYTE (x));
+ rtx simplified = simplify_subreg (mode, tem, GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x));
if (simplified)
tem = simplified;
if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
- && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
&& subreg_lowpart_p (x))
{
rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,