cfgloop.h (struct loop): Update comment.
* cfgloop.h (struct loop): Update comment. * cse.c (cse_main): Remove obsolete comment. * expr.h (gen_cond_trap): Move prototype under functions provided by optabs.c. (canonicalize_condition, get_condition): Move to... * rtl.h (canonicalize_condition, get_condition): ...here. (branch_target_load_optimize): Add comment that this function is in bt-load.c. * loop.c (canonicalize_condition, get_condition): Move to... * rtlanal.c (canonicalize_condition, get_condition): ...here. * sched-deps.c (get_condition): Rename to sched_get_condition. (add_dependence): Update this caller. From-SVN: r89995
This commit is contained in:
parent
65e9700cc0
commit
75473b0257
|
@ -1,3 +1,19 @@
|
||||||
|
2004-11-02 Steven Bosscher <stevenb@suse.de>
|
||||||
|
|
||||||
|
* cfgloop.h (struct loop): Update comment.
|
||||||
|
* cse.c (cse_main): Remove obsolete comment.
|
||||||
|
|
||||||
|
* expr.h (gen_cond_trap): Move prototype under functions provided
|
||||||
|
by optabs.c.
|
||||||
|
(canonicalize_condition, get_condition): Move to...
|
||||||
|
* rtl.h (canonicalize_condition, get_condition): ...here.
|
||||||
|
(branch_target_load_optimize): Add comment that this function is
|
||||||
|
in bt-load.c.
|
||||||
|
* loop.c (canonicalize_condition, get_condition): Move to...
|
||||||
|
* rtlanal.c (canonicalize_condition, get_condition): ...here.
|
||||||
|
* sched-deps.c (get_condition): Rename to sched_get_condition.
|
||||||
|
(add_dependence): Update this caller.
|
||||||
|
|
||||||
2004-11-02 Andrew Pinski <pinskia@physics.uc.edu>
|
2004-11-02 Andrew Pinski <pinskia@physics.uc.edu>
|
||||||
|
|
||||||
PR tree-opt/16808
|
PR tree-opt/16808
|
||||||
|
|
|
@ -144,7 +144,7 @@ struct loop
|
||||||
void *aux;
|
void *aux;
|
||||||
|
|
||||||
/* The following are currently used by loop.c but they are likely to
|
/* The following are currently used by loop.c but they are likely to
|
||||||
disappear as loop.c is converted to use the CFG. */
|
disappear when loop.c is replaced and removed. */
|
||||||
|
|
||||||
/* The NOTE_INSN_LOOP_BEG. */
|
/* The NOTE_INSN_LOOP_BEG. */
|
||||||
rtx start;
|
rtx start;
|
||||||
|
|
|
@ -6775,11 +6775,7 @@ cse_main (rtx f, int nregs, FILE *file)
|
||||||
|
|
||||||
/* Process a single basic block. FROM and TO and the limits of the basic
|
/* Process a single basic block. FROM and TO and the limits of the basic
|
||||||
block. NEXT_BRANCH points to the branch path when following jumps or
|
block. NEXT_BRANCH points to the branch path when following jumps or
|
||||||
a null path when not following jumps.
|
a null path when not following jumps. */
|
||||||
|
|
||||||
AROUND_LOOP is nonzero if we are to try to cse around to the start of a
|
|
||||||
loop. This is true when we are being called for the last time on a
|
|
||||||
block and this CSE pass is before loop.c. */
|
|
||||||
|
|
||||||
static rtx
|
static rtx
|
||||||
cse_basic_block (rtx from, rtx to, struct branch_path *next_branch)
|
cse_basic_block (rtx from, rtx to, struct branch_path *next_branch)
|
||||||
|
|
16
gcc/expr.h
16
gcc/expr.h
|
@ -298,6 +298,9 @@ extern void emit_cmp_and_jump_insns (rtx, rtx, enum rtx_code, rtx,
|
||||||
/* Generate code to indirectly jump to a location given in the rtx LOC. */
|
/* Generate code to indirectly jump to a location given in the rtx LOC. */
|
||||||
extern void emit_indirect_jump (rtx);
|
extern void emit_indirect_jump (rtx);
|
||||||
|
|
||||||
|
/* Generate a conditional trap instruction. */
|
||||||
|
extern rtx gen_cond_trap (enum rtx_code, rtx, rtx, rtx);
|
||||||
|
|
||||||
#include "insn-config.h"
|
#include "insn-config.h"
|
||||||
|
|
||||||
#ifdef HAVE_conditional_move
|
#ifdef HAVE_conditional_move
|
||||||
|
@ -329,19 +332,6 @@ extern rtx emit_store_flag (rtx, enum rtx_code, rtx, rtx, enum machine_mode,
|
||||||
/* Like emit_store_flag, but always succeeds. */
|
/* Like emit_store_flag, but always succeeds. */
|
||||||
extern rtx emit_store_flag_force (rtx, enum rtx_code, rtx, rtx,
|
extern rtx emit_store_flag_force (rtx, enum rtx_code, rtx, rtx,
|
||||||
enum machine_mode, int, int);
|
enum machine_mode, int, int);
|
||||||
|
|
||||||
/* Functions from loop.c: */
|
|
||||||
|
|
||||||
/* Given an insn and condition, return a canonical description of
|
|
||||||
the test being made. */
|
|
||||||
extern rtx canonicalize_condition (rtx, rtx, int, rtx *, rtx, int, int);
|
|
||||||
|
|
||||||
/* Given a JUMP_INSN, return a canonical description of the test
|
|
||||||
being made. */
|
|
||||||
extern rtx get_condition (rtx, rtx *, int, int);
|
|
||||||
|
|
||||||
/* Generate a conditional trap instruction. */
|
|
||||||
extern rtx gen_cond_trap (enum rtx_code, rtx, rtx, rtx);
|
|
||||||
|
|
||||||
/* Functions from builtins.c: */
|
/* Functions from builtins.c: */
|
||||||
extern rtx expand_builtin (tree, rtx, rtx, enum machine_mode, int);
|
extern rtx expand_builtin (tree, rtx, rtx, enum machine_mode, int);
|
||||||
|
|
315
gcc/loop.c
315
gcc/loop.c
|
@ -10438,319 +10438,8 @@ update_reg_last_use (rtx x, rtx insn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given an insn INSN and condition COND, return the condition in a
|
/* Similar to rtlanal.c:get_condition, except that we also put an
|
||||||
canonical form to simplify testing by callers. Specifically:
|
invariant last unless both operands are invariants. */
|
||||||
|
|
||||||
(1) The code will always be a comparison operation (EQ, NE, GT, etc.).
|
|
||||||
(2) Both operands will be machine operands; (cc0) will have been replaced.
|
|
||||||
(3) If an operand is a constant, it will be the second operand.
|
|
||||||
(4) (LE x const) will be replaced with (LT x <const+1>) and similarly
|
|
||||||
for GE, GEU, and LEU.
|
|
||||||
|
|
||||||
If the condition cannot be understood, or is an inequality floating-point
|
|
||||||
comparison which needs to be reversed, 0 will be returned.
|
|
||||||
|
|
||||||
If REVERSE is nonzero, then reverse the condition prior to canonizing it.
|
|
||||||
|
|
||||||
If EARLIEST is nonzero, it is a pointer to a place where the earliest
|
|
||||||
insn used in locating the condition was found. If a replacement test
|
|
||||||
of the condition is desired, it should be placed in front of that
|
|
||||||
insn and we will be sure that the inputs are still valid.
|
|
||||||
|
|
||||||
If WANT_REG is nonzero, we wish the condition to be relative to that
|
|
||||||
register, if possible. Therefore, do not canonicalize the condition
|
|
||||||
further. If ALLOW_CC_MODE is nonzero, allow the condition returned
|
|
||||||
to be a compare to a CC mode register.
|
|
||||||
|
|
||||||
If VALID_AT_INSN_P, the condition must be valid at both *EARLIEST
|
|
||||||
and at INSN. */
|
|
||||||
|
|
||||||
rtx
|
|
||||||
canonicalize_condition (rtx insn, rtx cond, int reverse, rtx *earliest,
|
|
||||||
rtx want_reg, int allow_cc_mode, int valid_at_insn_p)
|
|
||||||
{
|
|
||||||
enum rtx_code code;
|
|
||||||
rtx prev = insn;
|
|
||||||
rtx set;
|
|
||||||
rtx tem;
|
|
||||||
rtx op0, op1;
|
|
||||||
int reverse_code = 0;
|
|
||||||
enum machine_mode mode;
|
|
||||||
|
|
||||||
code = GET_CODE (cond);
|
|
||||||
mode = GET_MODE (cond);
|
|
||||||
op0 = XEXP (cond, 0);
|
|
||||||
op1 = XEXP (cond, 1);
|
|
||||||
|
|
||||||
if (reverse)
|
|
||||||
code = reversed_comparison_code (cond, insn);
|
|
||||||
if (code == UNKNOWN)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (earliest)
|
|
||||||
*earliest = insn;
|
|
||||||
|
|
||||||
/* If we are comparing a register with zero, see if the register is set
|
|
||||||
in the previous insn to a COMPARE or a comparison operation. Perform
|
|
||||||
the same tests as a function of STORE_FLAG_VALUE as find_comparison_args
|
|
||||||
in cse.c */
|
|
||||||
|
|
||||||
while ((GET_RTX_CLASS (code) == RTX_COMPARE
|
|
||||||
|| GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
|
|
||||||
&& op1 == CONST0_RTX (GET_MODE (op0))
|
|
||||||
&& op0 != want_reg)
|
|
||||||
{
|
|
||||||
/* Set nonzero when we find something of interest. */
|
|
||||||
rtx x = 0;
|
|
||||||
|
|
||||||
#ifdef HAVE_cc0
|
|
||||||
/* If comparison with cc0, import actual comparison from compare
|
|
||||||
insn. */
|
|
||||||
if (op0 == cc0_rtx)
|
|
||||||
{
|
|
||||||
if ((prev = prev_nonnote_insn (prev)) == 0
|
|
||||||
|| !NONJUMP_INSN_P (prev)
|
|
||||||
|| (set = single_set (prev)) == 0
|
|
||||||
|| SET_DEST (set) != cc0_rtx)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
op0 = SET_SRC (set);
|
|
||||||
op1 = CONST0_RTX (GET_MODE (op0));
|
|
||||||
if (earliest)
|
|
||||||
*earliest = prev;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* If this is a COMPARE, pick up the two things being compared. */
|
|
||||||
if (GET_CODE (op0) == COMPARE)
|
|
||||||
{
|
|
||||||
op1 = XEXP (op0, 1);
|
|
||||||
op0 = XEXP (op0, 0);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (!REG_P (op0))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Go back to the previous insn. Stop if it is not an INSN. We also
|
|
||||||
stop if it isn't a single set or if it has a REG_INC note because
|
|
||||||
we don't want to bother dealing with it. */
|
|
||||||
|
|
||||||
if ((prev = prev_nonnote_insn (prev)) == 0
|
|
||||||
|| !NONJUMP_INSN_P (prev)
|
|
||||||
|| FIND_REG_INC_NOTE (prev, NULL_RTX))
|
|
||||||
break;
|
|
||||||
|
|
||||||
set = set_of (op0, prev);
|
|
||||||
|
|
||||||
if (set
|
|
||||||
&& (GET_CODE (set) != SET
|
|
||||||
|| !rtx_equal_p (SET_DEST (set), op0)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* If this is setting OP0, get what it sets it to if it looks
|
|
||||||
relevant. */
|
|
||||||
if (set)
|
|
||||||
{
|
|
||||||
enum machine_mode inner_mode = GET_MODE (SET_DEST (set));
|
|
||||||
#ifdef FLOAT_STORE_FLAG_VALUE
|
|
||||||
REAL_VALUE_TYPE fsfv;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ??? We may not combine comparisons done in a CCmode with
|
|
||||||
comparisons not done in a CCmode. This is to aid targets
|
|
||||||
like Alpha that have an IEEE compliant EQ instruction, and
|
|
||||||
a non-IEEE compliant BEQ instruction. The use of CCmode is
|
|
||||||
actually artificial, simply to prevent the combination, but
|
|
||||||
should not affect other platforms.
|
|
||||||
|
|
||||||
However, we must allow VOIDmode comparisons to match either
|
|
||||||
CCmode or non-CCmode comparison, because some ports have
|
|
||||||
modeless comparisons inside branch patterns.
|
|
||||||
|
|
||||||
??? This mode check should perhaps look more like the mode check
|
|
||||||
in simplify_comparison in combine. */
|
|
||||||
|
|
||||||
if ((GET_CODE (SET_SRC (set)) == COMPARE
|
|
||||||
|| (((code == NE
|
|
||||||
|| (code == LT
|
|
||||||
&& GET_MODE_CLASS (inner_mode) == MODE_INT
|
|
||||||
&& (GET_MODE_BITSIZE (inner_mode)
|
|
||||||
<= HOST_BITS_PER_WIDE_INT)
|
|
||||||
&& (STORE_FLAG_VALUE
|
|
||||||
& ((HOST_WIDE_INT) 1
|
|
||||||
<< (GET_MODE_BITSIZE (inner_mode) - 1))))
|
|
||||||
#ifdef FLOAT_STORE_FLAG_VALUE
|
|
||||||
|| (code == LT
|
|
||||||
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
|
|
||||||
&& (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
|
|
||||||
REAL_VALUE_NEGATIVE (fsfv)))
|
|
||||||
#endif
|
|
||||||
))
|
|
||||||
&& COMPARISON_P (SET_SRC (set))))
|
|
||||||
&& (((GET_MODE_CLASS (mode) == MODE_CC)
|
|
||||||
== (GET_MODE_CLASS (inner_mode) == MODE_CC))
|
|
||||||
|| mode == VOIDmode || inner_mode == VOIDmode))
|
|
||||||
x = SET_SRC (set);
|
|
||||||
else if (((code == EQ
|
|
||||||
|| (code == GE
|
|
||||||
&& (GET_MODE_BITSIZE (inner_mode)
|
|
||||||
<= HOST_BITS_PER_WIDE_INT)
|
|
||||||
&& GET_MODE_CLASS (inner_mode) == MODE_INT
|
|
||||||
&& (STORE_FLAG_VALUE
|
|
||||||
& ((HOST_WIDE_INT) 1
|
|
||||||
<< (GET_MODE_BITSIZE (inner_mode) - 1))))
|
|
||||||
#ifdef FLOAT_STORE_FLAG_VALUE
|
|
||||||
|| (code == GE
|
|
||||||
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
|
|
||||||
&& (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
|
|
||||||
REAL_VALUE_NEGATIVE (fsfv)))
|
|
||||||
#endif
|
|
||||||
))
|
|
||||||
&& COMPARISON_P (SET_SRC (set))
|
|
||||||
&& (((GET_MODE_CLASS (mode) == MODE_CC)
|
|
||||||
== (GET_MODE_CLASS (inner_mode) == MODE_CC))
|
|
||||||
|| mode == VOIDmode || inner_mode == VOIDmode))
|
|
||||||
|
|
||||||
{
|
|
||||||
reverse_code = 1;
|
|
||||||
x = SET_SRC (set);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (reg_set_p (op0, prev))
|
|
||||||
/* If this sets OP0, but not directly, we have to give up. */
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (x)
|
|
||||||
{
|
|
||||||
/* If the caller is expecting the condition to be valid at INSN,
|
|
||||||
make sure X doesn't change before INSN. */
|
|
||||||
if (valid_at_insn_p)
|
|
||||||
if (modified_in_p (x, prev) || modified_between_p (x, prev, insn))
|
|
||||||
break;
|
|
||||||
if (COMPARISON_P (x))
|
|
||||||
code = GET_CODE (x);
|
|
||||||
if (reverse_code)
|
|
||||||
{
|
|
||||||
code = reversed_comparison_code (x, prev);
|
|
||||||
if (code == UNKNOWN)
|
|
||||||
return 0;
|
|
||||||
reverse_code = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
op0 = XEXP (x, 0), op1 = XEXP (x, 1);
|
|
||||||
if (earliest)
|
|
||||||
*earliest = prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If constant is first, put it last. */
|
|
||||||
if (CONSTANT_P (op0))
|
|
||||||
code = swap_condition (code), tem = op0, op0 = op1, op1 = tem;
|
|
||||||
|
|
||||||
/* If OP0 is the result of a comparison, we weren't able to find what
|
|
||||||
was really being compared, so fail. */
|
|
||||||
if (!allow_cc_mode
|
|
||||||
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Canonicalize any ordered comparison with integers involving equality
|
|
||||||
if we can do computations in the relevant mode and we do not
|
|
||||||
overflow. */
|
|
||||||
|
|
||||||
if (GET_MODE_CLASS (GET_MODE (op0)) != MODE_CC
|
|
||||||
&& GET_CODE (op1) == CONST_INT
|
|
||||||
&& GET_MODE (op0) != VOIDmode
|
|
||||||
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
|
|
||||||
{
|
|
||||||
HOST_WIDE_INT const_val = INTVAL (op1);
|
|
||||||
unsigned HOST_WIDE_INT uconst_val = const_val;
|
|
||||||
unsigned HOST_WIDE_INT max_val
|
|
||||||
= (unsigned HOST_WIDE_INT) GET_MODE_MASK (GET_MODE (op0));
|
|
||||||
|
|
||||||
switch (code)
|
|
||||||
{
|
|
||||||
case LE:
|
|
||||||
if ((unsigned HOST_WIDE_INT) const_val != max_val >> 1)
|
|
||||||
code = LT, op1 = gen_int_mode (const_val + 1, GET_MODE (op0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* When cross-compiling, const_val might be sign-extended from
|
|
||||||
BITS_PER_WORD to HOST_BITS_PER_WIDE_INT */
|
|
||||||
case GE:
|
|
||||||
if ((HOST_WIDE_INT) (const_val & max_val)
|
|
||||||
!= (((HOST_WIDE_INT) 1
|
|
||||||
<< (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
|
|
||||||
code = GT, op1 = gen_int_mode (const_val - 1, GET_MODE (op0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LEU:
|
|
||||||
if (uconst_val < max_val)
|
|
||||||
code = LTU, op1 = gen_int_mode (uconst_val + 1, GET_MODE (op0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GEU:
|
|
||||||
if (uconst_val != 0)
|
|
||||||
code = GTU, op1 = gen_int_mode (uconst_val - 1, GET_MODE (op0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Never return CC0; return zero instead. */
|
|
||||||
if (CC0_P (op0))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Given a jump insn JUMP, return the condition that will cause it to branch
|
|
||||||
to its JUMP_LABEL. If the condition cannot be understood, or is an
|
|
||||||
inequality floating-point comparison which needs to be reversed, 0 will
|
|
||||||
be returned.
|
|
||||||
|
|
||||||
If EARLIEST is nonzero, it is a pointer to a place where the earliest
|
|
||||||
insn used in locating the condition was found. If a replacement test
|
|
||||||
of the condition is desired, it should be placed in front of that
|
|
||||||
insn and we will be sure that the inputs are still valid. If EARLIEST
|
|
||||||
is null, the returned condition will be valid at INSN.
|
|
||||||
|
|
||||||
If ALLOW_CC_MODE is nonzero, allow the condition returned to be a
|
|
||||||
compare CC mode register.
|
|
||||||
|
|
||||||
VALID_AT_INSN_P is the same as for canonicalize_condition. */
|
|
||||||
|
|
||||||
rtx
|
|
||||||
get_condition (rtx jump, rtx *earliest, int allow_cc_mode, int valid_at_insn_p)
|
|
||||||
{
|
|
||||||
rtx cond;
|
|
||||||
int reverse;
|
|
||||||
rtx set;
|
|
||||||
|
|
||||||
/* If this is not a standard conditional jump, we can't parse it. */
|
|
||||||
if (!JUMP_P (jump)
|
|
||||||
|| ! any_condjump_p (jump))
|
|
||||||
return 0;
|
|
||||||
set = pc_set (jump);
|
|
||||||
|
|
||||||
cond = XEXP (SET_SRC (set), 0);
|
|
||||||
|
|
||||||
/* If this branches to JUMP_LABEL when the condition is false, reverse
|
|
||||||
the condition. */
|
|
||||||
reverse
|
|
||||||
= GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
|
|
||||||
&& XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump);
|
|
||||||
|
|
||||||
return canonicalize_condition (jump, cond, reverse, earliest, NULL_RTX,
|
|
||||||
allow_cc_mode, valid_at_insn_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Similar to above routine, except that we also put an invariant last
|
|
||||||
unless both operands are invariants. */
|
|
||||||
|
|
||||||
static rtx
|
static rtx
|
||||||
get_condition_for_loop (const struct loop *loop, rtx x)
|
get_condition_for_loop (const struct loop *loop, rtx x)
|
||||||
|
|
11
gcc/rtl.h
11
gcc/rtl.h
|
@ -1657,6 +1657,15 @@ extern bool keep_with_call_p (rtx);
|
||||||
extern bool label_is_jump_target_p (rtx, rtx);
|
extern bool label_is_jump_target_p (rtx, rtx);
|
||||||
extern int insn_rtx_cost (rtx);
|
extern int insn_rtx_cost (rtx);
|
||||||
|
|
||||||
|
/* Given an insn and condition, return a canonical description of
|
||||||
|
the test being made. */
|
||||||
|
extern rtx canonicalize_condition (rtx, rtx, int, rtx *, rtx, int, int);
|
||||||
|
|
||||||
|
/* Given a JUMP_INSN, return a canonical description of the test
|
||||||
|
being made. */
|
||||||
|
extern rtx get_condition (rtx, rtx *, int, int);
|
||||||
|
|
||||||
|
|
||||||
/* flow.c */
|
/* flow.c */
|
||||||
|
|
||||||
extern rtx find_use_as_address (rtx, rtx, HOST_WIDE_INT);
|
extern rtx find_use_as_address (rtx, rtx, HOST_WIDE_INT);
|
||||||
|
@ -2017,6 +2026,8 @@ extern void print_inline_rtx (FILE *, rtx, int);
|
||||||
/* In loop.c */
|
/* In loop.c */
|
||||||
extern void init_loop (void);
|
extern void init_loop (void);
|
||||||
extern void loop_optimize (rtx, FILE *, int);
|
extern void loop_optimize (rtx, FILE *, int);
|
||||||
|
|
||||||
|
/* In bt-load.c */
|
||||||
extern void branch_target_load_optimize (bool);
|
extern void branch_target_load_optimize (bool);
|
||||||
|
|
||||||
/* In function.c */
|
/* In function.c */
|
||||||
|
|
312
gcc/rtlanal.c
312
gcc/rtlanal.c
|
@ -4333,3 +4333,315 @@ insn_rtx_cost (rtx pat)
|
||||||
cost = rtx_cost (SET_SRC (set), SET);
|
cost = rtx_cost (SET_SRC (set), SET);
|
||||||
return cost > 0 ? cost : COSTS_N_INSNS (1);
|
return cost > 0 ? cost : COSTS_N_INSNS (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Given an insn INSN and condition COND, return the condition in a
|
||||||
|
canonical form to simplify testing by callers. Specifically:
|
||||||
|
|
||||||
|
(1) The code will always be a comparison operation (EQ, NE, GT, etc.).
|
||||||
|
(2) Both operands will be machine operands; (cc0) will have been replaced.
|
||||||
|
(3) If an operand is a constant, it will be the second operand.
|
||||||
|
(4) (LE x const) will be replaced with (LT x <const+1>) and similarly
|
||||||
|
for GE, GEU, and LEU.
|
||||||
|
|
||||||
|
If the condition cannot be understood, or is an inequality floating-point
|
||||||
|
comparison which needs to be reversed, 0 will be returned.
|
||||||
|
|
||||||
|
If REVERSE is nonzero, then reverse the condition prior to canonizing it.
|
||||||
|
|
||||||
|
If EARLIEST is nonzero, it is a pointer to a place where the earliest
|
||||||
|
insn used in locating the condition was found. If a replacement test
|
||||||
|
of the condition is desired, it should be placed in front of that
|
||||||
|
insn and we will be sure that the inputs are still valid.
|
||||||
|
|
||||||
|
If WANT_REG is nonzero, we wish the condition to be relative to that
|
||||||
|
register, if possible. Therefore, do not canonicalize the condition
|
||||||
|
further. If ALLOW_CC_MODE is nonzero, allow the condition returned
|
||||||
|
to be a compare to a CC mode register.
|
||||||
|
|
||||||
|
If VALID_AT_INSN_P, the condition must be valid at both *EARLIEST
|
||||||
|
and at INSN. */
|
||||||
|
|
||||||
|
rtx
|
||||||
|
canonicalize_condition (rtx insn, rtx cond, int reverse, rtx *earliest,
|
||||||
|
rtx want_reg, int allow_cc_mode, int valid_at_insn_p)
|
||||||
|
{
|
||||||
|
enum rtx_code code;
|
||||||
|
rtx prev = insn;
|
||||||
|
rtx set;
|
||||||
|
rtx tem;
|
||||||
|
rtx op0, op1;
|
||||||
|
int reverse_code = 0;
|
||||||
|
enum machine_mode mode;
|
||||||
|
|
||||||
|
code = GET_CODE (cond);
|
||||||
|
mode = GET_MODE (cond);
|
||||||
|
op0 = XEXP (cond, 0);
|
||||||
|
op1 = XEXP (cond, 1);
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
code = reversed_comparison_code (cond, insn);
|
||||||
|
if (code == UNKNOWN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (earliest)
|
||||||
|
*earliest = insn;
|
||||||
|
|
||||||
|
/* If we are comparing a register with zero, see if the register is set
|
||||||
|
in the previous insn to a COMPARE or a comparison operation. Perform
|
||||||
|
the same tests as a function of STORE_FLAG_VALUE as find_comparison_args
|
||||||
|
in cse.c */
|
||||||
|
|
||||||
|
while ((GET_RTX_CLASS (code) == RTX_COMPARE
|
||||||
|
|| GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
|
||||||
|
&& op1 == CONST0_RTX (GET_MODE (op0))
|
||||||
|
&& op0 != want_reg)
|
||||||
|
{
|
||||||
|
/* Set nonzero when we find something of interest. */
|
||||||
|
rtx x = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_cc0
|
||||||
|
/* If comparison with cc0, import actual comparison from compare
|
||||||
|
insn. */
|
||||||
|
if (op0 == cc0_rtx)
|
||||||
|
{
|
||||||
|
if ((prev = prev_nonnote_insn (prev)) == 0
|
||||||
|
|| !NONJUMP_INSN_P (prev)
|
||||||
|
|| (set = single_set (prev)) == 0
|
||||||
|
|| SET_DEST (set) != cc0_rtx)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
op0 = SET_SRC (set);
|
||||||
|
op1 = CONST0_RTX (GET_MODE (op0));
|
||||||
|
if (earliest)
|
||||||
|
*earliest = prev;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If this is a COMPARE, pick up the two things being compared. */
|
||||||
|
if (GET_CODE (op0) == COMPARE)
|
||||||
|
{
|
||||||
|
op1 = XEXP (op0, 1);
|
||||||
|
op0 = XEXP (op0, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (!REG_P (op0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Go back to the previous insn. Stop if it is not an INSN. We also
|
||||||
|
stop if it isn't a single set or if it has a REG_INC note because
|
||||||
|
we don't want to bother dealing with it. */
|
||||||
|
|
||||||
|
if ((prev = prev_nonnote_insn (prev)) == 0
|
||||||
|
|| !NONJUMP_INSN_P (prev)
|
||||||
|
|| FIND_REG_INC_NOTE (prev, NULL_RTX))
|
||||||
|
break;
|
||||||
|
|
||||||
|
set = set_of (op0, prev);
|
||||||
|
|
||||||
|
if (set
|
||||||
|
&& (GET_CODE (set) != SET
|
||||||
|
|| !rtx_equal_p (SET_DEST (set), op0)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If this is setting OP0, get what it sets it to if it looks
|
||||||
|
relevant. */
|
||||||
|
if (set)
|
||||||
|
{
|
||||||
|
enum machine_mode inner_mode = GET_MODE (SET_DEST (set));
|
||||||
|
#ifdef FLOAT_STORE_FLAG_VALUE
|
||||||
|
REAL_VALUE_TYPE fsfv;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ??? We may not combine comparisons done in a CCmode with
|
||||||
|
comparisons not done in a CCmode. This is to aid targets
|
||||||
|
like Alpha that have an IEEE compliant EQ instruction, and
|
||||||
|
a non-IEEE compliant BEQ instruction. The use of CCmode is
|
||||||
|
actually artificial, simply to prevent the combination, but
|
||||||
|
should not affect other platforms.
|
||||||
|
|
||||||
|
However, we must allow VOIDmode comparisons to match either
|
||||||
|
CCmode or non-CCmode comparison, because some ports have
|
||||||
|
modeless comparisons inside branch patterns.
|
||||||
|
|
||||||
|
??? This mode check should perhaps look more like the mode check
|
||||||
|
in simplify_comparison in combine. */
|
||||||
|
|
||||||
|
if ((GET_CODE (SET_SRC (set)) == COMPARE
|
||||||
|
|| (((code == NE
|
||||||
|
|| (code == LT
|
||||||
|
&& GET_MODE_CLASS (inner_mode) == MODE_INT
|
||||||
|
&& (GET_MODE_BITSIZE (inner_mode)
|
||||||
|
<= HOST_BITS_PER_WIDE_INT)
|
||||||
|
&& (STORE_FLAG_VALUE
|
||||||
|
& ((HOST_WIDE_INT) 1
|
||||||
|
<< (GET_MODE_BITSIZE (inner_mode) - 1))))
|
||||||
|
#ifdef FLOAT_STORE_FLAG_VALUE
|
||||||
|
|| (code == LT
|
||||||
|
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
|
||||||
|
&& (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
|
||||||
|
REAL_VALUE_NEGATIVE (fsfv)))
|
||||||
|
#endif
|
||||||
|
))
|
||||||
|
&& COMPARISON_P (SET_SRC (set))))
|
||||||
|
&& (((GET_MODE_CLASS (mode) == MODE_CC)
|
||||||
|
== (GET_MODE_CLASS (inner_mode) == MODE_CC))
|
||||||
|
|| mode == VOIDmode || inner_mode == VOIDmode))
|
||||||
|
x = SET_SRC (set);
|
||||||
|
else if (((code == EQ
|
||||||
|
|| (code == GE
|
||||||
|
&& (GET_MODE_BITSIZE (inner_mode)
|
||||||
|
<= HOST_BITS_PER_WIDE_INT)
|
||||||
|
&& GET_MODE_CLASS (inner_mode) == MODE_INT
|
||||||
|
&& (STORE_FLAG_VALUE
|
||||||
|
& ((HOST_WIDE_INT) 1
|
||||||
|
<< (GET_MODE_BITSIZE (inner_mode) - 1))))
|
||||||
|
#ifdef FLOAT_STORE_FLAG_VALUE
|
||||||
|
|| (code == GE
|
||||||
|
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
|
||||||
|
&& (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
|
||||||
|
REAL_VALUE_NEGATIVE (fsfv)))
|
||||||
|
#endif
|
||||||
|
))
|
||||||
|
&& COMPARISON_P (SET_SRC (set))
|
||||||
|
&& (((GET_MODE_CLASS (mode) == MODE_CC)
|
||||||
|
== (GET_MODE_CLASS (inner_mode) == MODE_CC))
|
||||||
|
|| mode == VOIDmode || inner_mode == VOIDmode))
|
||||||
|
|
||||||
|
{
|
||||||
|
reverse_code = 1;
|
||||||
|
x = SET_SRC (set);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (reg_set_p (op0, prev))
|
||||||
|
/* If this sets OP0, but not directly, we have to give up. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
/* If the caller is expecting the condition to be valid at INSN,
|
||||||
|
make sure X doesn't change before INSN. */
|
||||||
|
if (valid_at_insn_p)
|
||||||
|
if (modified_in_p (x, prev) || modified_between_p (x, prev, insn))
|
||||||
|
break;
|
||||||
|
if (COMPARISON_P (x))
|
||||||
|
code = GET_CODE (x);
|
||||||
|
if (reverse_code)
|
||||||
|
{
|
||||||
|
code = reversed_comparison_code (x, prev);
|
||||||
|
if (code == UNKNOWN)
|
||||||
|
return 0;
|
||||||
|
reverse_code = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
op0 = XEXP (x, 0), op1 = XEXP (x, 1);
|
||||||
|
if (earliest)
|
||||||
|
*earliest = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If constant is first, put it last. */
|
||||||
|
if (CONSTANT_P (op0))
|
||||||
|
code = swap_condition (code), tem = op0, op0 = op1, op1 = tem;
|
||||||
|
|
||||||
|
/* If OP0 is the result of a comparison, we weren't able to find what
|
||||||
|
was really being compared, so fail. */
|
||||||
|
if (!allow_cc_mode
|
||||||
|
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Canonicalize any ordered comparison with integers involving equality
|
||||||
|
if we can do computations in the relevant mode and we do not
|
||||||
|
overflow. */
|
||||||
|
|
||||||
|
if (GET_MODE_CLASS (GET_MODE (op0)) != MODE_CC
|
||||||
|
&& GET_CODE (op1) == CONST_INT
|
||||||
|
&& GET_MODE (op0) != VOIDmode
|
||||||
|
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
|
||||||
|
{
|
||||||
|
HOST_WIDE_INT const_val = INTVAL (op1);
|
||||||
|
unsigned HOST_WIDE_INT uconst_val = const_val;
|
||||||
|
unsigned HOST_WIDE_INT max_val
|
||||||
|
= (unsigned HOST_WIDE_INT) GET_MODE_MASK (GET_MODE (op0));
|
||||||
|
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case LE:
|
||||||
|
if ((unsigned HOST_WIDE_INT) const_val != max_val >> 1)
|
||||||
|
code = LT, op1 = gen_int_mode (const_val + 1, GET_MODE (op0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* When cross-compiling, const_val might be sign-extended from
|
||||||
|
BITS_PER_WORD to HOST_BITS_PER_WIDE_INT */
|
||||||
|
case GE:
|
||||||
|
if ((HOST_WIDE_INT) (const_val & max_val)
|
||||||
|
!= (((HOST_WIDE_INT) 1
|
||||||
|
<< (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
|
||||||
|
code = GT, op1 = gen_int_mode (const_val - 1, GET_MODE (op0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LEU:
|
||||||
|
if (uconst_val < max_val)
|
||||||
|
code = LTU, op1 = gen_int_mode (uconst_val + 1, GET_MODE (op0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEU:
|
||||||
|
if (uconst_val != 0)
|
||||||
|
code = GTU, op1 = gen_int_mode (uconst_val - 1, GET_MODE (op0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Never return CC0; return zero instead. */
|
||||||
|
if (CC0_P (op0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given a jump insn JUMP, return the condition that will cause it to branch
|
||||||
|
to its JUMP_LABEL. If the condition cannot be understood, or is an
|
||||||
|
inequality floating-point comparison which needs to be reversed, 0 will
|
||||||
|
be returned.
|
||||||
|
|
||||||
|
If EARLIEST is nonzero, it is a pointer to a place where the earliest
|
||||||
|
insn used in locating the condition was found. If a replacement test
|
||||||
|
of the condition is desired, it should be placed in front of that
|
||||||
|
insn and we will be sure that the inputs are still valid. If EARLIEST
|
||||||
|
is null, the returned condition will be valid at INSN.
|
||||||
|
|
||||||
|
If ALLOW_CC_MODE is nonzero, allow the condition returned to be a
|
||||||
|
compare CC mode register.
|
||||||
|
|
||||||
|
VALID_AT_INSN_P is the same as for canonicalize_condition. */
|
||||||
|
|
||||||
|
rtx
|
||||||
|
get_condition (rtx jump, rtx *earliest, int allow_cc_mode, int valid_at_insn_p)
|
||||||
|
{
|
||||||
|
rtx cond;
|
||||||
|
int reverse;
|
||||||
|
rtx set;
|
||||||
|
|
||||||
|
/* If this is not a standard conditional jump, we can't parse it. */
|
||||||
|
if (!JUMP_P (jump)
|
||||||
|
|| ! any_condjump_p (jump))
|
||||||
|
return 0;
|
||||||
|
set = pc_set (jump);
|
||||||
|
|
||||||
|
cond = XEXP (SET_SRC (set), 0);
|
||||||
|
|
||||||
|
/* If this branches to JUMP_LABEL when the condition is false, reverse
|
||||||
|
the condition. */
|
||||||
|
reverse
|
||||||
|
= GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
|
||||||
|
&& XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump);
|
||||||
|
|
||||||
|
return canonicalize_condition (jump, cond, reverse, earliest, NULL_RTX,
|
||||||
|
allow_cc_mode, valid_at_insn_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ static void sched_analyze_1 (struct deps *, rtx, rtx);
|
||||||
static void sched_analyze_2 (struct deps *, rtx, rtx);
|
static void sched_analyze_2 (struct deps *, rtx, rtx);
|
||||||
static void sched_analyze_insn (struct deps *, rtx, rtx, rtx);
|
static void sched_analyze_insn (struct deps *, rtx, rtx, rtx);
|
||||||
|
|
||||||
static rtx get_condition (rtx);
|
static rtx sched_get_condition (rtx);
|
||||||
static int conditions_mutex_p (rtx, rtx);
|
static int conditions_mutex_p (rtx, rtx);
|
||||||
|
|
||||||
/* Return nonzero if a load of the memory reference MEM can cause a trap. */
|
/* Return nonzero if a load of the memory reference MEM can cause a trap. */
|
||||||
|
@ -138,7 +138,7 @@ find_insn_list (rtx insn, rtx list)
|
||||||
/* Find the condition under which INSN is executed. */
|
/* Find the condition under which INSN is executed. */
|
||||||
|
|
||||||
static rtx
|
static rtx
|
||||||
get_condition (rtx insn)
|
sched_get_condition (rtx insn)
|
||||||
{
|
{
|
||||||
rtx pat = PATTERN (insn);
|
rtx pat = PATTERN (insn);
|
||||||
rtx src;
|
rtx src;
|
||||||
|
@ -218,8 +218,8 @@ add_dependence (rtx insn, rtx elem, enum reg_note dep_type)
|
||||||
be dependent. */
|
be dependent. */
|
||||||
if (!CALL_P (insn) && !CALL_P (elem))
|
if (!CALL_P (insn) && !CALL_P (elem))
|
||||||
{
|
{
|
||||||
cond1 = get_condition (insn);
|
cond1 = sched_get_condition (insn);
|
||||||
cond2 = get_condition (elem);
|
cond2 = sched_get_condition (elem);
|
||||||
if (cond1 && cond2
|
if (cond1 && cond2
|
||||||
&& conditions_mutex_p (cond1, cond2)
|
&& conditions_mutex_p (cond1, cond2)
|
||||||
/* Make sure first instruction doesn't affect condition of second
|
/* Make sure first instruction doesn't affect condition of second
|
||||||
|
|
Loading…
Reference in New Issue