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
8 changed files with 350 additions and 336 deletions
|
@ -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>
|
||||
|
||||
PR tree-opt/16808
|
||||
|
|
|
@ -144,7 +144,7 @@ struct loop
|
|||
void *aux;
|
||||
|
||||
/* 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. */
|
||||
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
|
||||
block. NEXT_BRANCH points to the branch path when following jumps or
|
||||
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. */
|
||||
a null path when not following jumps. */
|
||||
|
||||
static rtx
|
||||
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. */
|
||||
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"
|
||||
|
||||
#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. */
|
||||
extern rtx emit_store_flag_force (rtx, enum rtx_code, rtx, rtx,
|
||||
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: */
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
/* Similar to above routine, except that we also put an invariant last
|
||||
unless both operands are invariants. */
|
||||
/* Similar to rtlanal.c:get_condition, except that we also put an
|
||||
invariant last unless both operands are invariants. */
|
||||
|
||||
static rtx
|
||||
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 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 */
|
||||
|
||||
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 */
|
||||
extern void init_loop (void);
|
||||
extern void loop_optimize (rtx, FILE *, int);
|
||||
|
||||
/* In bt-load.c */
|
||||
extern void branch_target_load_optimize (bool);
|
||||
|
||||
/* 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);
|
||||
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_insn (struct deps *, rtx, rtx, rtx);
|
||||
|
||||
static rtx get_condition (rtx);
|
||||
static rtx sched_get_condition (rtx);
|
||||
static int conditions_mutex_p (rtx, rtx);
|
||||
|
||||
/* 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. */
|
||||
|
||||
static rtx
|
||||
get_condition (rtx insn)
|
||||
sched_get_condition (rtx insn)
|
||||
{
|
||||
rtx pat = PATTERN (insn);
|
||||
rtx src;
|
||||
|
@ -218,8 +218,8 @@ add_dependence (rtx insn, rtx elem, enum reg_note dep_type)
|
|||
be dependent. */
|
||||
if (!CALL_P (insn) && !CALL_P (elem))
|
||||
{
|
||||
cond1 = get_condition (insn);
|
||||
cond2 = get_condition (elem);
|
||||
cond1 = sched_get_condition (insn);
|
||||
cond2 = sched_get_condition (elem);
|
||||
if (cond1 && cond2
|
||||
&& conditions_mutex_p (cond1, cond2)
|
||||
/* Make sure first instruction doesn't affect condition of second
|
||||
|
|
Loading…
Add table
Reference in a new issue