#include "config.h"
#include "system.h"
#include "rtl.h"
#include "flags.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "insn-config.h"
#include "insn-flags.h"
#include "insn-attr.h"
#include "recog.h"
#include "expr.h"
#include "real.h"
#include "except.h"
#include "toplev.h"
static rtx *jump_chain;
rtx forced_labels;
static int max_jump_chain;
int can_reach_end;
static int cross_jump_death_matters = 0;
static int init_label_info PROTO((rtx));
static void delete_barrier_successors PROTO((rtx));
static void mark_all_labels PROTO((rtx, int));
static rtx delete_unreferenced_labels PROTO((rtx));
static void delete_noop_moves PROTO((rtx));
static int calculate_can_reach_end PROTO((rtx, int, int));
static int duplicate_loop_exit_test PROTO((rtx));
static void find_cross_jump PROTO((rtx, rtx, int, rtx *, rtx *));
static void do_cross_jump PROTO((rtx, rtx, rtx));
static int jump_back_p PROTO((rtx, rtx));
static int tension_vector_labels PROTO((rtx, int));
static void mark_jump_label PROTO((rtx, rtx, int));
static void delete_computation PROTO((rtx));
static void delete_from_jump_chain PROTO((rtx));
static int delete_labelref_insn PROTO((rtx, rtx, int));
static void mark_modified_reg PROTO((rtx, rtx));
static void redirect_tablejump PROTO((rtx, rtx));
static void jump_optimize_1 PROTO ((rtx, int, int, int, int));
#ifndef HAVE_cc0
static rtx find_insert_position PROTO((rtx, rtx));
#endif
void
jump_optimize (f, cross_jump, noop_moves, after_regscan)
rtx f;
int cross_jump;
int noop_moves;
int after_regscan;
{
jump_optimize_1 (f, cross_jump, noop_moves, after_regscan, 0);
}
void
rebuild_jump_labels (f)
rtx f;
{
jump_optimize_1 (f, 0, 0, 0, 1);
}
static void
jump_optimize_1 (f, cross_jump, noop_moves, after_regscan, mark_labels_only)
rtx f;
int cross_jump;
int noop_moves;
int after_regscan;
int mark_labels_only;
{
register rtx insn, next;
int changed;
int old_max_reg;
int first = 1;
int max_uid = 0;
rtx last_insn;
cross_jump_death_matters = (cross_jump == 2);
max_uid = init_label_info (f) + 1;
if (flag_exceptions && cross_jump)
init_insn_eh_region (f, max_uid);
delete_barrier_successors (f);
max_jump_chain = max_uid * 14 / 10;
jump_chain = (rtx *) alloca (max_jump_chain * sizeof (rtx));
bzero ((char *) jump_chain, max_jump_chain * sizeof (rtx));
mark_all_labels (f, cross_jump);
for (insn = forced_labels; insn; insn = XEXP (insn, 1))
LABEL_NUSES (XEXP (insn, 0))++;
check_exception_handler_labels ();
for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
LABEL_NUSES (XEXP (insn, 0))++;
if (mark_labels_only)
return;
exception_optimize ();
last_insn = delete_unreferenced_labels (f);
if (!optimize)
{
if (calculate_can_reach_end (last_insn, 1, 0))
can_reach_end = 1;
for (insn = f; insn; insn = NEXT_INSN (insn))
INSN_DELETED_P (insn) = 0;
jump_chain = 0;
return;
}
#ifdef HAVE_return
if (HAVE_return)
{
insn = get_last_insn ();
while (insn && GET_CODE (insn) == NOTE)
insn = PREV_INSN (insn);
if (insn && GET_CODE (insn) != BARRIER)
{
emit_jump_insn (gen_return ());
emit_barrier ();
}
}
#endif
if (noop_moves)
delete_noop_moves (f);
if (! reload_completed && after_regscan)
for (insn = f; insn; insn = next)
{
rtx set = single_set (insn);
next = NEXT_INSN (insn);
if (set && GET_CODE (SET_DEST (set)) == REG
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
&& REGNO_FIRST_UID (REGNO (SET_DEST (set))) == INSN_UID (insn)
&& REGNO_LAST_NOTE_UID (REGNO (SET_DEST (set))) == INSN_UID (insn)
&& ! side_effects_p (SET_SRC (set))
&& ! find_reg_note (insn, REG_RETVAL, 0))
delete_insn (insn);
}
changed = 1;
old_max_reg = max_reg_num ();
while (changed)
{
changed = 0;
for (insn = f; insn; insn = next)
{
rtx reallabelprev;
rtx temp, temp1, temp2, temp3, temp4, temp5, temp6;
rtx nlabel;
int this_is_simplejump, this_is_condjump, reversep = 0;
int this_is_condjump_in_parallel;
#if 0
if (reload_completed && !first && !flag_no_peephole)
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
peephole (insn);
#endif
next = NEXT_INSN (insn);
if (after_regscan && GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
&& (temp1 = next_nonnote_insn (insn)) != 0
&& simplejump_p (temp1))
{
temp = PREV_INSN (insn);
if (duplicate_loop_exit_test (insn))
{
changed = 1;
next = NEXT_INSN (temp);
continue;
}
}
if (GET_CODE (insn) != JUMP_INSN)
continue;
this_is_simplejump = simplejump_p (insn);
this_is_condjump = condjump_p (insn);
this_is_condjump_in_parallel = condjump_in_parallel_p (insn);
if (GET_CODE (PATTERN (insn)) == ADDR_VEC)
changed |= tension_vector_labels (PATTERN (insn), 0);
if (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
changed |= tension_vector_labels (PATTERN (insn), 1);
if (GET_CODE (PATTERN (insn)) == ADDR_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
{
int i;
rtx pat = PATTERN (insn);
int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC;
int len = XVECLEN (pat, diff_vec_p);
rtx dispatch = prev_real_insn (insn);
rtx set;
for (i = 0; i < len; i++)
if (XEXP (XVECEXP (pat, diff_vec_p, i), 0)
!= XEXP (XVECEXP (pat, diff_vec_p, 0), 0))
break;
if (i == len
&& dispatch != 0
&& GET_CODE (dispatch) == JUMP_INSN
&& JUMP_LABEL (dispatch) != 0
&& ! ((set = single_set (dispatch)) != NULL
&& (GET_CODE (SET_SRC (set)) == IF_THEN_ELSE))
&& next_real_insn (JUMP_LABEL (dispatch)) == insn)
{
redirect_tablejump (dispatch,
XEXP (XVECEXP (pat, diff_vec_p, 0), 0));
changed = 1;
}
}
reallabelprev = prev_active_insn (JUMP_LABEL (insn));
if (JUMP_LABEL (insn)
&& (next_active_insn (JUMP_LABEL (insn)) == 0
|| GET_CODE (PATTERN (next_active_insn (JUMP_LABEL (insn))))
== RETURN))
changed |= redirect_jump (insn, NULL_RTX);
if (reallabelprev == insn && condjump_p (insn))
{
next = next_real_insn (JUMP_LABEL (insn));
delete_jump (insn);
changed = 1;
continue;
}
if (this_is_simplejump
&& (temp = prev_nonnote_insn (insn)) != 0
&& GET_CODE (temp) == INSN && GET_CODE (PATTERN (temp)) == USE
&& (temp1 = prev_nonnote_insn (JUMP_LABEL (insn))) != 0
&& (GET_CODE (temp1) == BARRIER
|| (GET_CODE (temp1) == INSN
&& rtx_equal_p (PATTERN (temp), PATTERN (temp1))))
&& ! ((temp2 = prev_nonnote_insn (temp)) != 0
&& temp2 == JUMP_LABEL (insn)
&& LABEL_NUSES (temp2) == 1))
{
if (GET_CODE (temp1) == BARRIER)
{
emit_insn_after (PATTERN (temp), temp1);
temp1 = NEXT_INSN (temp1);
}
delete_insn (temp);
redirect_jump (insn, get_label_before (temp1));
reallabelprev = prev_real_insn (temp1);
changed = 1;
}
if (this_is_simplejump
&& (temp3 = prev_active_insn (insn)) != 0
&& GET_CODE (temp3) == INSN
&& (temp4 = single_set (temp3)) != 0
&& GET_CODE (temp1 = SET_DEST (temp4)) == REG
&& (! SMALL_REGISTER_CLASSES
|| REGNO (temp1) >= FIRST_PSEUDO_REGISTER)
&& (temp2 = next_active_insn (insn)) != 0
&& GET_CODE (temp2) == INSN
&& (temp4 = single_set (temp2)) != 0
&& rtx_equal_p (SET_DEST (temp4), temp1)
&& ! side_effects_p (SET_SRC (temp4))
&& ! may_trap_p (SET_SRC (temp4))
&& (REG_NOTES (temp2) == 0
|| ((REG_NOTE_KIND (REG_NOTES (temp2)) == REG_EQUAL
|| REG_NOTE_KIND (REG_NOTES (temp2)) == REG_EQUIV)
&& XEXP (REG_NOTES (temp2), 1) == 0
&& rtx_equal_p (XEXP (REG_NOTES (temp2), 0),
SET_SRC (temp4))))
&& (temp = prev_active_insn (temp3)) != 0
&& condjump_p (temp) && ! simplejump_p (temp)
&& prev_real_insn (JUMP_LABEL (temp)) == insn
&& no_labels_between_p (insn, JUMP_LABEL (temp))
&& no_labels_between_p (JUMP_LABEL (temp), temp2)
&& (reallabelprev == temp2
|| ((temp5 = next_active_insn (temp2)) != 0
&& simplejump_p (temp5)
&& JUMP_LABEL (temp5) == JUMP_LABEL (insn))))
{
rtx target = JUMP_LABEL (temp);
int nuses = LABEL_NUSES (target);
rtx p;
#ifdef HAVE_cc0
rtx q;
#endif
for (p = temp; nuses && p; p = prev_nonnote_insn (p))
{
if (GET_CODE (p) == JUMP_INSN)
{
if (condjump_p (p) && ! simplejump_p (p)
&& JUMP_LABEL (p) == target)
{
nuses--;
if (nuses == 0)
break;
}
else
break;
}
else if (GET_CODE (p) == CALL_INSN)
break;
}
#ifdef HAVE_cc0
q = prev_nonnote_insn (p);
if (q && GET_RTX_CLASS (GET_CODE (q)) == 'i'
&& sets_cc0_p (PATTERN (q)))
p = q;
#endif
if (p)
p = PREV_INSN (p);
if (nuses == 0 && p
&& no_labels_between_p (p, insn)
&& ! reg_referenced_between_p (temp1, p, NEXT_INSN (temp3))
&& ! reg_set_between_p (temp1, p, temp3)
&& (GET_CODE (SET_SRC (temp4)) == CONST_INT
|| ! modified_between_p (SET_SRC (temp4), p, temp2))
&& ! regs_set_between_p (PATTERN (temp),
PREV_INSN (temp2),
NEXT_INSN (temp2)))
{
emit_insn_after_with_line_notes (PATTERN (temp2), p, temp2);
delete_insn (temp2);
next = next_active_insn (insn);
delete_insn (insn);
for (p = NEXT_INSN (p); p != next; p = NEXT_INSN (p))
if (GET_CODE (p) == JUMP_INSN)
redirect_jump (p, target);
changed = 1;
continue;
}
}
if (this_is_simplejump
&& (temp2 = next_active_insn (insn)) != 0
&& GET_CODE (temp2) == INSN
&& (temp4 = single_set (temp2)) != 0
&& GET_CODE (temp1 = SET_DEST (temp4)) == REG
&& (! SMALL_REGISTER_CLASSES
|| REGNO (temp1) >= FIRST_PSEUDO_REGISTER)
&& (temp3 = prev_active_insn (insn)) != 0
&& GET_CODE (temp3) == INSN
&& (temp4 = single_set (temp3)) != 0
&& rtx_equal_p (SET_DEST (temp4), temp1)
&& ! side_effects_p (SET_SRC (temp4))
&& ! may_trap_p (SET_SRC (temp4))
&& (REG_NOTES (temp3) == 0
|| ((REG_NOTE_KIND (REG_NOTES (temp3)) == REG_EQUAL
|| REG_NOTE_KIND (REG_NOTES (temp3)) == REG_EQUIV)
&& XEXP (REG_NOTES (temp3), 1) == 0
&& rtx_equal_p (XEXP (REG_NOTES (temp3), 0),
SET_SRC (temp4))))
&& (temp = prev_active_insn (temp3)) != 0
&& condjump_p (temp) && ! simplejump_p (temp)
&& prev_real_insn (JUMP_LABEL (temp)) == insn
&& no_labels_between_p (temp, insn))
{
rtx prev_label = JUMP_LABEL (temp);
rtx insert_after = prev_nonnote_insn (temp);
#ifdef HAVE_cc0
if (insert_after && GET_RTX_CLASS (GET_CODE (insert_after)) == 'i'
&& sets_cc0_p (PATTERN (insert_after)))
insert_after = prev_nonnote_insn (insert_after);
#endif
++LABEL_NUSES (prev_label);
if (insert_after
&& no_labels_between_p (insert_after, temp)
&& ! reg_referenced_between_p (temp1, insert_after, temp3)
&& ! reg_referenced_between_p (temp1, temp3,
NEXT_INSN (temp2))
&& ! reg_set_between_p (temp1, insert_after, temp)
&& ! modified_between_p (SET_SRC (temp4), insert_after, temp)
&& ! regs_set_between_p (PATTERN (temp),
PREV_INSN (temp3),
NEXT_INSN (temp3))
&& invert_jump (temp, JUMP_LABEL (insn)))
{
emit_insn_after_with_line_notes (PATTERN (temp3),
insert_after, temp3);
delete_insn (temp3);
delete_insn (insn);
next = temp2;
changed = 1;
}
if (prev_label && --LABEL_NUSES (prev_label) == 0)
delete_insn (prev_label);
if (changed)
continue;
}
#ifndef HAVE_cc0
if (! reload_completed
&& this_is_condjump && ! this_is_simplejump
&& BRANCH_COST >= 3
&& (temp = next_nonnote_insn (insn)) != 0
&& GET_CODE (temp) == INSN
&& REG_NOTES (temp) == 0
&& (reallabelprev == temp
|| ((temp2 = next_active_insn (temp)) != 0
&& simplejump_p (temp2)
&& JUMP_LABEL (temp2) == JUMP_LABEL (insn)))
&& (temp1 = single_set (temp)) != 0
&& (temp2 = SET_DEST (temp1), GET_CODE (temp2) == REG)
&& (! SMALL_REGISTER_CLASSES
|| REGNO (temp2) >= FIRST_PSEUDO_REGISTER)
&& GET_CODE (SET_SRC (temp1)) != REG
&& GET_CODE (SET_SRC (temp1)) != SUBREG
&& GET_CODE (SET_SRC (temp1)) != CONST_INT
&& ! side_effects_p (SET_SRC (temp1))
&& ! may_trap_p (SET_SRC (temp1))
&& rtx_cost (SET_SRC (temp1), SET) < 10)
{
rtx new = gen_reg_rtx (GET_MODE (temp2));
if ((temp3 = find_insert_position (insn, temp))
&& validate_change (temp, &SET_DEST (temp1), new, 0))
{
next = emit_insn_after (gen_move_insn (temp2, new), insn);
emit_insn_after_with_line_notes (PATTERN (temp),
PREV_INSN (temp3), temp);
delete_insn (temp);
reallabelprev = prev_active_insn (JUMP_LABEL (insn));
if (after_regscan)
{
reg_scan_update (temp3, NEXT_INSN (next), old_max_reg);
old_max_reg = max_reg_num ();
}
}
}
if (! reload_completed
&& this_is_condjump && ! this_is_simplejump
&& BRANCH_COST >= 4
&& (temp = next_nonnote_insn (insn)) != 0
&& GET_CODE (temp) == INSN
&& REG_NOTES (temp) == 0
&& (temp3 = next_nonnote_insn (temp)) != 0
&& GET_CODE (temp3) == INSN
&& REG_NOTES (temp3) == 0
&& (reallabelprev == temp3
|| ((temp2 = next_active_insn (temp3)) != 0
&& simplejump_p (temp2)
&& JUMP_LABEL (temp2) == JUMP_LABEL (insn)))
&& (temp1 = single_set (temp)) != 0
&& (temp2 = SET_DEST (temp1), GET_CODE (temp2) == REG)
&& GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT
&& (! SMALL_REGISTER_CLASSES
|| REGNO (temp2) >= FIRST_PSEUDO_REGISTER)
&& ! side_effects_p (SET_SRC (temp1))
&& ! may_trap_p (SET_SRC (temp1))
&& rtx_cost (SET_SRC (temp1), SET) < 10
&& (temp4 = single_set (temp3)) != 0
&& rtx_equal_p (SET_DEST (temp4), temp2)
&& ! side_effects_p (SET_SRC (temp4))
&& ! may_trap_p (SET_SRC (temp4))
&& rtx_cost (SET_SRC (temp4), SET) < 10)
{
rtx new = gen_reg_rtx (GET_MODE (temp2));
if ((temp5 = find_insert_position (insn, temp))
&& (temp6 = find_insert_position (insn, temp3))
&& validate_change (temp, &SET_DEST (temp1), new, 0))
{
if (temp5 != insn)
temp6 = temp5;
next = emit_insn_after (gen_move_insn (temp2, new), insn);
emit_insn_after_with_line_notes (PATTERN (temp),
PREV_INSN (temp6), temp);
emit_insn_after_with_line_notes
(replace_rtx (PATTERN (temp3), temp2, new),
PREV_INSN (temp6), temp3);
delete_insn (temp);
delete_insn (temp3);
reallabelprev = prev_active_insn (JUMP_LABEL (insn));
if (after_regscan)
{
reg_scan_update (temp6, NEXT_INSN (next), old_max_reg);
old_max_reg = max_reg_num ();
}
}
}
if (! reload_completed
&& after_regscan
&& this_is_condjump && ! this_is_simplejump
&& BRANCH_COST >= 4
&& (temp = next_nonnote_insn (insn)) != 0
&& GET_CODE (temp) == INSN
&& REG_NOTES (temp) == 0
&& (temp3 = next_nonnote_insn (temp)) != 0
&& GET_CODE (temp3) == INSN
&& REG_NOTES (temp3) == 0
&& (reallabelprev == temp3
|| ((temp2 = next_active_insn (temp3)) != 0
&& simplejump_p (temp2)
&& JUMP_LABEL (temp2) == JUMP_LABEL (insn)))
&& (temp1 = single_set (temp)) != 0
&& (temp5 = SET_DEST (temp1),
(GET_CODE (temp5) == REG
|| (GET_CODE (temp5) == SUBREG
&& (temp5 = SUBREG_REG (temp5),
GET_CODE (temp5) == REG))))
&& REGNO (temp5) >= FIRST_PSEUDO_REGISTER
&& REGNO_FIRST_UID (REGNO (temp5)) == INSN_UID (temp)
&& REGNO_LAST_UID (REGNO (temp5)) == INSN_UID (temp3)
&& ! side_effects_p (SET_SRC (temp1))
&& ! may_trap_p (SET_SRC (temp1))
&& rtx_cost (SET_SRC (temp1), SET) < 10
&& (temp4 = single_set (temp3)) != 0
&& (temp2 = SET_DEST (temp4), GET_CODE (temp2) == REG)
&& GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT
&& (! SMALL_REGISTER_CLASSES
|| REGNO (temp2) >= FIRST_PSEUDO_REGISTER)
&& rtx_equal_p (SET_DEST (temp4), temp2)
&& ! side_effects_p (SET_SRC (temp4))
&& ! may_trap_p (SET_SRC (temp4))
&& rtx_cost (SET_SRC (temp4), SET) < 10)
{
rtx new = gen_reg_rtx (GET_MODE (temp2));
if ((temp5 = find_insert_position (insn, temp))
&& (temp6 = find_insert_position (insn, temp3))
&& validate_change (temp3, &SET_DEST (temp4), new, 0))
{
if (temp5 != insn)
temp6 = temp5;
next = emit_insn_after (gen_move_insn (temp2, new), insn);
emit_insn_after_with_line_notes (PATTERN (temp),
PREV_INSN (temp6), temp);
emit_insn_after_with_line_notes (PATTERN (temp3),
PREV_INSN (temp6), temp3);
delete_insn (temp);
delete_insn (temp3);
reallabelprev = prev_active_insn (JUMP_LABEL (insn));
if (after_regscan)
{
reg_scan_update (temp6, NEXT_INSN (next), old_max_reg);
old_max_reg = max_reg_num ();
}
}
}
#endif
if (
! reload_completed
&& this_is_condjump && ! this_is_simplejump
&& (temp = next_nonnote_insn (insn)) != 0
&& GET_CODE (temp) == INSN
&& GET_CODE (PATTERN (temp)) == SET
&& GET_CODE (temp1 = SET_DEST (PATTERN (temp))) == REG
&& (! SMALL_REGISTER_CLASSES
|| REGNO (temp1) >= FIRST_PSEUDO_REGISTER)
&& ! side_effects_p (temp2 = SET_SRC (PATTERN (temp)))
&& ! may_trap_p (temp2)
&& (((temp3 = reg_set_last (temp1, insn)) != 0
&& ! (SMALL_REGISTER_CLASSES && GET_CODE (temp3) == REG
&& REGNO (temp3) < FIRST_PSEUDO_REGISTER))
|| (temp3 = temp1, 1))
&& (reallabelprev == temp
|| ((temp4 = next_active_insn (temp)) != 0
&& simplejump_p (temp4)
&& JUMP_LABEL (temp4) == JUMP_LABEL (insn)))
&& (temp4 = get_condition (insn, &temp5)) != 0
&& GET_MODE (XEXP (temp4, 0)) != BLKmode
#ifdef HAVE_cc0
&& ! ((temp6 = prev_nonnote_insn (insn)) != 0
&& GET_CODE (temp6) == INSN
&& (sets_cc0_p (PATTERN (temp6)) == -1
|| (sets_cc0_p (PATTERN (temp6)) == 1
&& FIND_REG_INC_NOTE (temp6, NULL_RTX))))
#endif
)
{
#ifdef HAVE_conditional_move
{
enum rtx_code code = GET_CODE (temp4);
rtx var = temp1;
rtx cond0, cond1, aval, bval;
rtx target;
cond0 = gen_reg_rtx (GET_MODE (XEXP (temp4, 0)));
if (GET_CODE (XEXP (temp4, 1)) == CONST_INT
|| GET_CODE (XEXP (temp4, 1)) == CONST_DOUBLE)
cond1 = XEXP (temp4, 1);
else
cond1 = gen_reg_rtx (GET_MODE (XEXP (temp4, 1)));
aval = temp3;
bval = temp2;
start_sequence ();
target = emit_conditional_move (var, code,
cond0, cond1, VOIDmode,
aval, bval, GET_MODE (var),
(code == LTU || code == GEU
|| code == LEU || code == GTU));
if (target)
{
rtx seq1,seq2,last;
seq2 = get_insns ();
end_sequence ();
start_sequence ();
emit_move_insn (cond0, XEXP (temp4, 0));
if (cond1 != XEXP (temp4, 1))
emit_move_insn (cond1, XEXP (temp4, 1));
seq1 = get_insns ();
end_sequence ();
emit_insns_before (seq1, temp5);
last = emit_insns_after (seq2, insn);
delete_insn (temp);
next = NEXT_INSN (insn);
delete_jump (insn);
if (after_regscan)
{
reg_scan_update (seq1, NEXT_INSN (last), old_max_reg);
old_max_reg = max_reg_num ();
}
changed = 1;
continue;
}
else
end_sequence ();
}
#endif
if (GET_MODE_CLASS (GET_MODE (temp1)) == MODE_INT
&& ((GET_CODE (temp3) == CONST_INT)
|| (temp3 = temp1,
((BRANCH_COST >= 2
&& temp2 == const0_rtx)
|| BRANCH_COST >= 3)))
&& (((BRANCH_COST >= 2
|| STORE_FLAG_VALUE == -1
|| (STORE_FLAG_VALUE == 1
&& GET_CODE (temp3) == CONST_INT
&& exact_log2 (INTVAL (temp3)) >= 0))
&& (reversep = 0, temp2 == const0_rtx))
|| ((BRANCH_COST >= 2
|| STORE_FLAG_VALUE == -1
|| (STORE_FLAG_VALUE == 1
&& GET_CODE (temp2) == CONST_INT
&& exact_log2 (INTVAL (temp2)) >= 0))
&& temp3 == const0_rtx
&& (reversep = can_reverse_comparison_p (temp4, insn)))
|| (BRANCH_COST >= 2
&& GET_CODE (temp2) == CONST_INT
&& GET_CODE (temp3) == CONST_INT
&& ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp2)
|| ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp3)
&& (reversep = can_reverse_comparison_p (temp4,
insn)))))
|| BRANCH_COST >= 3)
)
{
enum rtx_code code = GET_CODE (temp4);
rtx uval, cval, var = temp1;
int normalizep;
rtx target;
if (reversep)
code = reverse_condition (code), uval = temp2, cval = temp3;
else
uval = temp3, cval = temp2;
normalizep = (cval != const0_rtx ? -1
: (uval == const1_rtx ? 1
: (GET_CODE (uval) == CONST_INT
&& (INTVAL (uval) & ~STORE_FLAG_VALUE) == 0)
? 0 : -1));
start_sequence ();
target = emit_store_flag (gen_reg_rtx (GET_MODE (var)), code,
XEXP (temp4, 0), XEXP (temp4, 1),
VOIDmode,
(code == LTU || code == LEU
|| code == GEU || code == GTU),
normalizep);
if (target)
{
rtx seq;
rtx before = insn;
seq = get_insns ();
end_sequence ();
emit_insns_before (seq, temp5);
start_sequence ();
if (cval != const0_rtx && uval != const0_rtx)
{
rtx tem1, tem2;
tem1 = expand_and (uval, target, NULL_RTX);
if (GET_CODE (cval) == CONST_INT
&& GET_CODE (uval) == CONST_INT
&& (INTVAL (cval) & INTVAL (uval)) == INTVAL (cval))
tem2 = cval;
else
{
tem2 = expand_unop (GET_MODE (var), one_cmpl_optab,
target, NULL_RTX, 0);
tem2 = expand_and (cval, tem2,
(GET_CODE (tem2) == REG
? tem2 : 0));
}
if (flag_expensive_optimizations)
target = 0;
target = expand_binop (GET_MODE (var), ior_optab,
tem1, tem2, target,
1, OPTAB_WIDEN);
}
else if (normalizep != 1)
{
if (uval == const0_rtx)
{
target = expand_unop (GET_MODE (var), one_cmpl_optab,
target, NULL_RTX, 0);
uval = cval;
}
target = expand_and (uval, target,
(GET_CODE (target) == REG
&& ! preserve_subexpressions_p ()
? target : NULL_RTX));
}
emit_move_insn (var, target);
seq = get_insns ();
end_sequence ();
#ifdef HAVE_cc0
if (reg_mentioned_p (cc0_rtx, PATTERN (before)))
before = prev_nonnote_insn (before);
#endif
emit_insns_before (seq, before);
delete_insn (temp);
next = NEXT_INSN (insn);
delete_jump (insn);
if (after_regscan)
{
reg_scan_update (seq, NEXT_INSN (next), old_max_reg);
old_max_reg = max_reg_num ();
}
changed = 1;
continue;
}
else
end_sequence ();
}
}
if ((BRANCH_COST >= 2
#ifdef HAVE_incscc
|| HAVE_incscc
#endif
#ifdef HAVE_decscc
|| HAVE_decscc
#endif
)
&& ! reload_completed
&& this_is_condjump && ! this_is_simplejump
&& (temp = next_nonnote_insn (insn)) != 0
&& (temp1 = single_set (temp)) != 0
&& (temp2 = SET_DEST (temp1),
GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT)
&& GET_CODE (SET_SRC (temp1)) == PLUS
&& (XEXP (SET_SRC (temp1), 1) == const1_rtx
|| XEXP (SET_SRC (temp1), 1) == constm1_rtx)
&& rtx_equal_p (temp2, XEXP (SET_SRC (temp1), 0))
&& ! side_effects_p (temp2)
&& ! may_trap_p (temp2)
&& (reallabelprev == temp
|| ((temp3 = next_active_insn (temp)) != 0
&& simplejump_p (temp3)
&& JUMP_LABEL (temp3) == JUMP_LABEL (insn)))
&& (temp3 = get_condition (insn, &temp4)) != 0
&& GET_MODE (XEXP (temp3, 0)) != BLKmode
&& can_reverse_comparison_p (temp3, insn))
{
rtx temp6, target = 0, seq, init_insn = 0, init = temp2;
enum rtx_code code = reverse_condition (GET_CODE (temp3));
start_sequence ();
if ((temp5 = prev_active_insn (insn)) != 0
&& no_labels_between_p (temp5, insn)
&& GET_CODE (temp5) == INSN
&& (temp6 = single_set (temp5)) != 0
&& rtx_equal_p (temp2, SET_DEST (temp6))
&& (CONSTANT_P (SET_SRC (temp6))
|| GET_CODE (SET_SRC (temp6)) == REG
|| GET_CODE (SET_SRC (temp6)) == SUBREG))
{
emit_insn (PATTERN (temp5));
init_insn = temp5;
init = SET_SRC (temp6);
}
if (CONSTANT_P (init)
|| ! reg_set_between_p (init, PREV_INSN (temp4), insn))
target = emit_store_flag (gen_reg_rtx (GET_MODE (temp2)), code,
XEXP (temp3, 0), XEXP (temp3, 1),
VOIDmode,
(code == LTU || code == LEU
|| code == GTU || code == GEU), 1);
if (target)
target = expand_binop (GET_MODE (temp2),
(XEXP (SET_SRC (temp1), 1) == const1_rtx
? add_optab : sub_optab),
temp2, target, temp2, 0, OPTAB_WIDEN);
if (target != 0)
{
if (target != temp2)
emit_move_insn (temp2, target);
seq = get_insns ();
end_sequence ();
emit_insns_before (seq, temp4);
delete_insn (temp);
if (init_insn)
delete_insn (init_insn);
next = NEXT_INSN (insn);
#ifdef HAVE_cc0
delete_insn (prev_nonnote_insn (insn));
#endif
delete_insn (insn);
if (after_regscan)
{
reg_scan_update (seq, NEXT_INSN (next), old_max_reg);
old_max_reg = max_reg_num ();
}
changed = 1;
continue;
}
else
end_sequence ();
}
#ifdef HAVE_cc0
else if (this_is_simplejump
&& (temp = prev_active_insn (insn))
&& no_labels_between_p (temp, insn)
&& GET_CODE (temp) == INSN
&& GET_CODE (PATTERN (temp)) == SET
&& GET_CODE (SET_DEST (PATTERN (temp))) == REG
&& CONSTANT_P (SET_SRC (PATTERN (temp)))
&& (temp1 = next_active_insn (JUMP_LABEL (insn)))
&& GET_CODE (temp1) == INSN
&& GET_CODE (PATTERN (temp1)) == SET
#ifdef HAVE_cc0
&& SET_SRC (PATTERN (temp1)) == SET_DEST (PATTERN (temp))
&& SET_DEST (PATTERN (temp1)) == cc0_rtx
&& (temp1 = next_nonnote_insn (temp1))
#else
&& GET_CODE (SET_SRC (PATTERN (temp1))) == COMPARE
&& XEXP (SET_SRC (PATTERN (temp1)), 1) == const0_rtx
&& (XEXP (SET_SRC (PATTERN (temp1)), 0)
== SET_DEST (PATTERN (temp)))
&& GET_CODE (SET_DEST (PATTERN (temp1))) == REG
&& (temp1 = find_next_ref (SET_DEST (PATTERN (temp1)), temp1))
#endif
&& condjump_p (temp1))
{
rtx choice = SET_SRC (PATTERN (temp1));
if (GET_CODE (choice) == IF_THEN_ELSE)
{
enum rtx_code code = GET_CODE (XEXP (choice, 0));
rtx val = SET_SRC (PATTERN (temp));
rtx cond
= simplify_relational_operation (code, GET_MODE (SET_DEST (PATTERN (temp))),
val, const0_rtx);
rtx ultimate;
if (cond == const_true_rtx)
ultimate = XEXP (choice, 1);
else if (cond == const0_rtx)
ultimate = XEXP (choice, 2);
else
ultimate = 0;
if (ultimate == pc_rtx)
ultimate = get_label_after (temp1);
else if (ultimate && GET_CODE (ultimate) != RETURN)
ultimate = XEXP (ultimate, 0);
if (ultimate && JUMP_LABEL(insn) != ultimate)
changed |= redirect_jump (insn, ultimate);
}
}
#endif
#if 0
else if (this_is_simplejump
&& (temp = prev_active_insn (insn))
&& no_labels_between_p (temp, insn)
&& condjump_p (temp)
&& (temp1 = prev_active_insn (temp))
&& no_labels_between_p (temp1, temp)
&& GET_CODE (temp1) == INSN
&& GET_CODE (PATTERN (temp1)) == SET
#ifdef HAVE_cc0
&& sets_cc0_p (PATTERN (temp1)) == 1
#else
&& GET_CODE (SET_SRC (PATTERN (temp1))) == COMPARE
&& GET_CODE (SET_DEST (PATTERN (temp1))) == REG
&& (temp == find_next_ref (SET_DEST (PATTERN (temp1)), temp1))
#endif
&& (temp2 = prev_active_insn (temp1))
&& no_labels_between_p (temp2, temp1)
&& condjump_p (temp2)
&& JUMP_LABEL (temp2) == next_nonnote_insn (NEXT_INSN (insn))
&& (temp3 = prev_active_insn (temp2))
&& no_labels_between_p (temp3, temp2)
&& GET_CODE (PATTERN (temp3)) == SET
&& rtx_equal_p (SET_DEST (PATTERN (temp3)),
SET_DEST (PATTERN (temp1)))
&& rtx_equal_p (SET_SRC (PATTERN (temp1)),
SET_SRC (PATTERN (temp3)))
&& ! inequality_comparisons_p (PATTERN (temp))
&& inequality_comparisons_p (PATTERN (temp2)))
{
rtx fallthrough_label = JUMP_LABEL (temp2);
++LABEL_NUSES (fallthrough_label);
if (swap_jump (temp2, JUMP_LABEL (insn)))
{
delete_insn (insn);
changed = 1;
}
if (--LABEL_NUSES (fallthrough_label) == 0)
delete_insn (fallthrough_label);
}
#endif
#if 0
else if (this_is_condjump
&& (temp = prev_active_insn (insn))
&& no_labels_between_p (temp, insn)
&& GET_CODE (temp) == INSN
&& GET_CODE (PATTERN (temp)) == SET
#ifdef HAVE_cc0
&& sets_cc0_p (PATTERN (temp)) == 1
&& GET_CODE (SET_SRC (PATTERN (temp))) == REG
#else
&& GET_CODE (SET_SRC (PATTERN (temp))) == COMPARE
&& XEXP (SET_SRC (PATTERN (temp)), 1) == const0_rtx
&& GET_CODE (XEXP (SET_SRC (PATTERN (temp)), 0)) == REG
&& GET_CODE (SET_DEST (PATTERN (temp))) == REG
&& insn == find_next_ref (SET_DEST (PATTERN (temp)), temp)
#endif
&& (temp1 = prev_active_insn (temp))
&& GET_CODE (temp1) == INSN
&& GET_CODE (PATTERN (temp1)) == SET
#ifdef HAVE_cc0
&& SET_SRC (PATTERN (temp)) == SET_DEST (PATTERN (temp1))
#else
&& (XEXP (SET_SRC (PATTERN (temp)), 0)
== SET_DEST (PATTERN (temp1)))
#endif
&& CONSTANT_P (SET_SRC (PATTERN (temp1)))
&& ! no_labels_between_p (temp1, temp))
{
rtx choice = SET_SRC (PATTERN (insn));
if (GET_CODE (choice) == IF_THEN_ELSE
&& (GET_CODE (XEXP (choice, 0)) == EQ
|| GET_CODE (XEXP (choice, 0)) == NE))
{
int want_nonzero = (GET_CODE (XEXP (choice, 0)) == NE);
rtx last_insn;
rtx ultimate;
rtx p;
if ((SET_SRC (PATTERN (temp1)) != const0_rtx)
== want_nonzero)
ultimate = XEXP (choice, 1);
else
ultimate = XEXP (choice, 2);
if (ultimate == pc_rtx)
ultimate = get_label_after (insn);
else
ultimate = XEXP (ultimate, 0);
last_insn = PREV_INSN (temp);
if (next_active_insn (last_insn)
!= next_active_insn (ultimate))
{
emit_barrier_after (last_insn);
p = emit_jump_insn_after (gen_jump (ultimate),
last_insn);
JUMP_LABEL (p) = ultimate;
++LABEL_NUSES (ultimate);
if (INSN_UID (ultimate) < max_jump_chain
&& INSN_CODE (p) < max_jump_chain)
{
jump_chain[INSN_UID (p)]
= jump_chain[INSN_UID (ultimate)];
jump_chain[INSN_UID (ultimate)] = p;
}
changed = 1;
continue;
}
}
}
#endif
else if (this_is_condjump
&& (temp = next_active_insn (insn)) != 0
&& simplejump_p (temp)
&& (next_active_insn (JUMP_LABEL (insn))
== next_active_insn (JUMP_LABEL (temp))))
{
rtx tem = temp;
if (flag_test_coverage && !reload_completed)
for (tem = insn; tem != temp; tem = NEXT_INSN (tem))
if (GET_CODE (tem) == NOTE && NOTE_LINE_NUMBER (tem) > 0)
break;
if (tem == temp)
{
delete_jump (insn);
changed = 1;
continue;
}
}
#ifdef HAVE_trap
else if (HAVE_trap
&& this_is_condjump && ! this_is_simplejump
&& reallabelprev != 0
&& GET_CODE (reallabelprev) == INSN
&& GET_CODE (PATTERN (reallabelprev)) == TRAP_IF
&& TRAP_CONDITION (PATTERN (reallabelprev)) == const_true_rtx
&& prev_active_insn (reallabelprev) == insn
&& no_labels_between_p (insn, reallabelprev)
&& (temp2 = get_condition (insn, &temp4))
&& can_reverse_comparison_p (temp2, insn))
{
rtx new = gen_cond_trap (reverse_condition (GET_CODE (temp2)),
XEXP (temp2, 0), XEXP (temp2, 1),
TRAP_CODE (PATTERN (reallabelprev)));
if (new)
{
emit_insn_before (new, temp4);
delete_insn (reallabelprev);
delete_jump (insn);
changed = 1;
continue;
}
}
else if (HAVE_trap && this_is_condjump
&& (temp = next_active_insn (JUMP_LABEL (insn)))
&& GET_CODE (temp) == INSN
&& GET_CODE (PATTERN (temp)) == TRAP_IF
&& (this_is_simplejump
|| (temp2 = get_condition (insn, &temp4))))
{
rtx tc = TRAP_CONDITION (PATTERN (temp));
if (tc == const_true_rtx
|| (! this_is_simplejump && rtx_equal_p (temp2, tc)))
{
rtx new;
if (this_is_simplejump)
{
emit_barrier_after (emit_insn_before (gen_trap (), insn));
delete_jump (insn);
changed = 1;
continue;
}
new = gen_cond_trap (GET_CODE (temp2), XEXP (temp2, 0),
XEXP (temp2, 1),
TRAP_CODE (PATTERN (temp)));
if (new)
{
emit_insn_before (new, temp4);
delete_jump (insn);
changed = 1;
continue;
}
}
else if (GET_RTX_CLASS (GET_CODE (tc)) == '<'
&& ! this_is_simplejump
&& swap_condition (GET_CODE (temp2)) == GET_CODE (tc)
&& rtx_equal_p (XEXP (tc, 0), XEXP (temp2, 0))
&& rtx_equal_p (XEXP (tc, 1), XEXP (temp2, 1))
&& redirect_jump (insn, get_label_after (temp)))
{
changed = 1;
continue;
}
}
#endif
else if ((this_is_condjump || this_is_condjump_in_parallel)
&& ! this_is_simplejump
&& reallabelprev != 0
&& GET_CODE (reallabelprev) == JUMP_INSN
&& prev_active_insn (reallabelprev) == insn
&& no_labels_between_p (insn, reallabelprev)
&& simplejump_p (reallabelprev))
{
rtx prev_uses = prev_nonnote_insn (reallabelprev);
rtx prev_label = JUMP_LABEL (insn);
if (prev_label)
++LABEL_NUSES (prev_label);
if (invert_jump (insn, JUMP_LABEL (reallabelprev)))
{
while (prev_uses && GET_CODE (prev_uses) == INSN
&& GET_CODE (PATTERN (prev_uses)) == USE)
{
rtx useless = prev_uses;
prev_uses = prev_nonnote_insn (prev_uses);
delete_insn (useless);
}
delete_insn (reallabelprev);
next = insn;
changed = 1;
}
if (prev_label && --LABEL_NUSES (prev_label) == 0)
delete_insn (prev_label);
continue;
}
else
{
nlabel = follow_jumps (JUMP_LABEL (insn));
if (nlabel != JUMP_LABEL (insn)
&& redirect_jump (insn, nlabel))
{
changed = 1;
next = insn;
}
{
rtx label1 = next_label (insn);
rtx range1end = label1 ? prev_active_insn (label1) : 0;
if (! first
&& (reload_completed ? ! flag_delayed_branch : 1)
&& condjump_p (insn)
&& label1 != 0
&& JUMP_LABEL (insn) == label1
&& LABEL_NUSES (label1) == 1
&& GET_CODE (range1end) == JUMP_INSN
&& simplejump_p (range1end))
{
rtx label2 = next_label (label1);
rtx range2end = label2 ? prev_active_insn (label2) : 0;
if (range1end != range2end
&& JUMP_LABEL (range1end) == label2
&& GET_CODE (range2end) == JUMP_INSN
&& GET_CODE (NEXT_INSN (range2end)) == BARRIER
&& invert_jump (insn, label1))
{
rtx range1beg = next_active_insn (insn);
rtx range2beg = next_active_insn (label1);
rtx range1after, range2after;
rtx range1before, range2before;
rtx rangenext;
while (PREV_INSN (range1beg)
&& GET_CODE (PREV_INSN (range1beg)) == NOTE)
range1beg = PREV_INSN (range1beg);
while (PREV_INSN (range2beg)
&& GET_CODE (PREV_INSN (range2beg)) == NOTE)
range2beg = PREV_INSN (range2beg);
range1beg = squeeze_notes (range1beg, range1end);
range2beg = squeeze_notes (range2beg, range2end);
range1before = PREV_INSN (range1beg);
range2before = PREV_INSN (range2beg);
range1after = NEXT_INSN (range1end);
range2after = NEXT_INSN (range2end);
NEXT_INSN (range1before) = range2beg;
PREV_INSN (range2beg) = range1before;
NEXT_INSN (range2end) = range1after;
PREV_INSN (range1after) = range2end;
NEXT_INSN (range2before) = range1beg;
PREV_INSN (range1beg) = range2before;
NEXT_INSN (range1end) = range2after;
PREV_INSN (range2after) = range1end;
for (;range2after != label2; range2after = rangenext)
{
rangenext = NEXT_INSN (range2after);
if (GET_CODE (range2after) == NOTE)
{
if (NOTE_LINE_NUMBER (range2after)
== NOTE_INSN_LOOP_END)
{
NEXT_INSN (PREV_INSN (range2after))
= rangenext;
PREV_INSN (rangenext)
= PREV_INSN (range2after);
PREV_INSN (range2after)
= PREV_INSN (range1beg);
NEXT_INSN (range2after) = range1beg;
NEXT_INSN (PREV_INSN (range1beg))
= range2after;
PREV_INSN (range1beg) = range2after;
}
else if (NOTE_LINE_NUMBER (range2after)
== NOTE_INSN_LOOP_BEG)
break;
}
}
changed = 1;
continue;
}
}
}
if (cross_jump && condjump_p (insn))
{
rtx newjpos, newlpos;
rtx x = prev_real_insn (JUMP_LABEL (insn));
if (x != 0 && ! jump_back_p (x, insn))
x = 0;
newjpos = 0;
if (x != 0)
find_cross_jump (insn, x, 2,
&newjpos, &newlpos);
if (newjpos != 0)
{
do_cross_jump (insn, newjpos, newlpos);
SET_SRC (PATTERN (insn))
= gen_rtx_LABEL_REF (VOIDmode, JUMP_LABEL (insn));
INSN_CODE (insn) = -1;
emit_barrier_after (insn);
if (INSN_UID (JUMP_LABEL (insn)) < max_jump_chain)
{
jump_chain[INSN_UID (insn)]
= jump_chain[INSN_UID (JUMP_LABEL (insn))];
jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
}
changed = 1;
next = insn;
}
}
if (cross_jump && simplejump_p (insn))
{
rtx newjpos, newlpos;
rtx target;
newjpos = 0;
find_cross_jump (insn, JUMP_LABEL (insn), 1,
&newjpos, &newlpos);
if (INSN_UID (JUMP_LABEL (insn)) < max_uid)
for (target = jump_chain[INSN_UID (JUMP_LABEL (insn))];
target != 0 && newjpos == 0;
target = jump_chain[INSN_UID (target)])
if (target != insn
&& JUMP_LABEL (target) == JUMP_LABEL (insn)
&& ! INSN_DELETED_P (target))
find_cross_jump (insn, target, 2,
&newjpos, &newlpos);
if (newjpos != 0)
{
do_cross_jump (insn, newjpos, newlpos);
changed = 1;
next = insn;
}
}
if (cross_jump && GET_CODE (PATTERN (insn)) == RETURN)
{
rtx newjpos, newlpos, target;
newjpos = 0;
for (target = jump_chain[0];
target != 0 && newjpos == 0;
target = jump_chain[INSN_UID (target)])
if (target != insn
&& ! INSN_DELETED_P (target)
&& GET_CODE (PATTERN (target)) == RETURN)
find_cross_jump (insn, target, 2,
&newjpos, &newlpos);
if (newjpos != 0)
{
do_cross_jump (insn, newjpos, newlpos);
changed = 1;
next = insn;
}
}
}
}
first = 0;
}
{
rtx last_note = 0;
for (insn = f; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) >= 0)
{
if (last_note
&& NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last_note)
&& NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last_note))
{
delete_insn (insn);
continue;
}
last_note = insn;
}
}
#ifdef HAVE_return
if (HAVE_return)
{
insn = get_last_insn ();
while (insn && GET_CODE (insn) == NOTE)
insn = PREV_INSN (insn);
if (insn && GET_CODE (insn) != BARRIER)
{
emit_jump_insn (gen_return ());
emit_barrier ();
}
}
#endif
if (calculate_can_reach_end (last_insn, 0, 1))
can_reach_end = 1;
jump_chain = 0;
}
static int
init_label_info (f)
rtx f;
{
int largest_uid = 0;
rtx insn;
for (insn = f; insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == CODE_LABEL)
LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
else if (GET_CODE (insn) == JUMP_INSN)
JUMP_LABEL (insn) = 0;
else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
{
rtx note, next;
for (note = REG_NOTES (insn); note; note = next)
{
next = XEXP (note, 1);
if (REG_NOTE_KIND (note) == REG_LABEL
&& ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
remove_note (insn, note);
}
}
if (INSN_UID (insn) > largest_uid)
largest_uid = INSN_UID (insn);
}
return largest_uid;
}
static void
delete_barrier_successors (f)
rtx f;
{
rtx insn;
for (insn = f; insn;)
{
if (GET_CODE (insn) == BARRIER)
{
insn = NEXT_INSN (insn);
while (insn != 0 && GET_CODE (insn) != CODE_LABEL)
{
if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
insn = NEXT_INSN (insn);
else
insn = delete_insn (insn);
}
}
else if (GET_CODE (insn) == JUMP_INSN
&& SET_SRC (PATTERN (insn)) == pc_rtx
&& SET_DEST (PATTERN (insn)) == pc_rtx)
insn = delete_insn (insn);
else
insn = NEXT_INSN (insn);
}
}
static void
mark_all_labels (f, cross_jump)
rtx f;
int cross_jump;
{
rtx insn;
for (insn = f; insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
mark_jump_label (PATTERN (insn), insn, cross_jump);
if (! INSN_DELETED_P (insn) && GET_CODE (insn) == JUMP_INSN)
{
if (JUMP_LABEL (insn) != 0 && simplejump_p (insn))
{
jump_chain[INSN_UID (insn)]
= jump_chain[INSN_UID (JUMP_LABEL (insn))];
jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
}
if (GET_CODE (PATTERN (insn)) == RETURN)
{
jump_chain[INSN_UID (insn)] = jump_chain[0];
jump_chain[0] = insn;
}
}
}
}
static rtx
delete_unreferenced_labels (f)
rtx f;
{
rtx final = NULL_RTX;
rtx insn;
for (insn = f; insn; )
{
if (GET_CODE (insn) == CODE_LABEL && LABEL_NUSES (insn) == 0)
insn = delete_insn (insn);
else
{
final = insn;
insn = NEXT_INSN (insn);
}
}
return final;
}
static void
delete_noop_moves (f)
rtx f;
{
rtx insn, next;
for (insn = f; insn; )
{
next = NEXT_INSN (insn);
if (GET_CODE (insn) == INSN)
{
register rtx body = PATTERN (insn);
#ifdef PUSH_ROUNDING
if (GET_CODE (body) == SET
&& SET_DEST (body) == stack_pointer_rtx
&& GET_CODE (SET_SRC (body)) == PLUS
&& XEXP (SET_SRC (body), 0) == stack_pointer_rtx
&& GET_CODE (XEXP (SET_SRC (body), 1)) == CONST_INT
&& INTVAL (XEXP (SET_SRC (body), 1)) > 0)
{
rtx p;
rtx stack_adjust_insn = insn;
int stack_adjust_amount = INTVAL (XEXP (SET_SRC (body), 1));
int total_pushed = 0;
int pushes = 0;
p = insn;
while (pushes < 3)
{
rtx pbody, dest;
p = next_nonnote_insn (p);
if (p == 0 || GET_CODE (p) != INSN)
break;
pbody = PATTERN (p);
if (GET_CODE (pbody) != SET)
break;
dest = SET_DEST (pbody);
if (GET_CODE (dest) == REG
&& GET_CODE (SET_SRC (pbody)) == REG
&& REGNO (dest) == REGNO (SET_SRC (pbody)))
continue;
if (! (GET_CODE (dest) == MEM
&& GET_CODE (XEXP (dest, 0)) == POST_INC
&& XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
break;
pushes++;
if (total_pushed + GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)))
> stack_adjust_amount)
break;
total_pushed += GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)));
}
if (total_pushed >= stack_adjust_amount)
{
delete_computation (stack_adjust_insn);
total_pushed = stack_adjust_amount;
}
else
XEXP (SET_SRC (PATTERN (stack_adjust_insn)), 1)
= GEN_INT (stack_adjust_amount - total_pushed);
p = insn;
while (total_pushed > 0)
{
rtx pbody, dest;
p = next_nonnote_insn (p);
if (GET_CODE (p) != INSN)
break;
pbody = PATTERN (p);
if (GET_CODE (pbody) != SET)
break;
dest = SET_DEST (pbody);
if (GET_CODE (dest) == REG
&& GET_CODE (SET_SRC (pbody)) == REG
&& REGNO (dest) == REGNO (SET_SRC (pbody)))
continue;
if (! (GET_CODE (dest) == MEM
&& GET_CODE (XEXP (dest, 0)) == POST_INC
&& XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
break;
total_pushed -= GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)));
if (total_pushed < 0)
{
emit_insn_before (gen_add2_insn (stack_pointer_rtx,
GEN_INT (- total_pushed)),
p);
break;
}
XEXP (dest, 0)
= plus_constant (stack_pointer_rtx, total_pushed);
}
}
#endif
if (GET_CODE (body) == SET
&& (SET_DEST (body) == SET_SRC (body)
|| (GET_CODE (SET_DEST (body)) == MEM
&& GET_CODE (SET_SRC (body)) == MEM
&& rtx_equal_p (SET_SRC (body), SET_DEST (body))))
&& ! (GET_CODE (SET_DEST (body)) == MEM
&& MEM_VOLATILE_P (SET_DEST (body)))
&& ! (GET_CODE (SET_SRC (body)) == MEM
&& MEM_VOLATILE_P (SET_SRC (body))))
delete_computation (insn);
else if (GET_CODE (body) == SET)
{
int sreg = true_regnum (SET_SRC (body));
int dreg = true_regnum (SET_DEST (body));
if (sreg == dreg && sreg >= 0)
delete_insn (insn);
else if (sreg >= 0 && dreg >= 0)
{
rtx trial;
rtx tem = find_equiv_reg (NULL_RTX, insn, 0,
sreg, NULL_PTR, dreg,
GET_MODE (SET_SRC (body)));
if (tem != 0
&& GET_MODE (tem) == GET_MODE (SET_DEST (body)))
{
if (! find_regno_note (insn, REG_UNUSED, dreg))
for (trial = prev_nonnote_insn (insn);
trial && GET_CODE (trial) != CODE_LABEL;
trial = prev_nonnote_insn (trial))
if (find_regno_note (trial, REG_DEAD, dreg))
{
remove_death (dreg, trial);
break;
}
if ((trial = find_regno_note (insn, REG_DEAD, sreg)))
{
PATTERN (insn)
= gen_rtx_USE (VOIDmode, XEXP (trial, 0));
INSN_CODE (insn) = -1;
REG_NOTES (insn) = trial;
XEXP (trial, 1) = NULL_RTX;
}
else
delete_insn (insn);
}
}
else if (dreg >= 0 && CONSTANT_P (SET_SRC (body))
&& find_equiv_reg (SET_SRC (body), insn, 0, dreg,
NULL_PTR, 0,
GET_MODE (SET_DEST (body))))
{
rtx in_insn = insn;
while (in_insn && GET_CODE (in_insn) != CODE_LABEL)
{
if ((GET_CODE (in_insn) == INSN
|| GET_CODE (in_insn) == JUMP_INSN)
&& find_regno_note (in_insn, REG_DEAD, dreg))
{
remove_death (dreg, in_insn);
break;
}
in_insn = PREV_INSN (in_insn);
}
delete_insn (insn);
}
}
else if (GET_CODE (body) == PARALLEL)
{
int i, sreg, dreg;
rtx tem;
for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
{
tem = XVECEXP (body, 0, i);
if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER)
continue;
if (GET_CODE (tem) != SET
|| (sreg = true_regnum (SET_SRC (tem))) < 0
|| (dreg = true_regnum (SET_DEST (tem))) < 0
|| dreg != sreg)
break;
}
if (i < 0)
delete_insn (insn);
}
else if (! BYTES_BIG_ENDIAN
&& GET_CODE (body) == SET
&& GET_CODE (SET_DEST (body)) == ZERO_EXTRACT
&& XEXP (SET_DEST (body), 2) == const0_rtx
&& XEXP (SET_DEST (body), 0) == SET_SRC (body)
&& ! (GET_CODE (SET_SRC (body)) == MEM
&& MEM_VOLATILE_P (SET_SRC (body))))
delete_insn (insn);
}
insn = next;
}
}
static int
calculate_can_reach_end (last, check_deleted, delete_final_note)
rtx last;
int check_deleted;
int delete_final_note;
{
rtx insn = last;
int n_labels = 1;
while (insn != NULL_RTX)
{
int ok = 0;
if (GET_CODE (insn) == CODE_LABEL && n_labels-- > 0)
ok = 1;
else if (GET_CODE (insn) == INSN)
ok = 1;
else if (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == RETURN)
ok = 1;
else if (GET_CODE (insn) == BARRIER)
ok = 1;
else if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
ok = 1;
if (ok != 1)
break;
insn = PREV_INSN (insn);
}
if (insn != NULL_RTX
&& GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END
&& (check_deleted == 0
|| ! INSN_DELETED_P (insn)))
{
if (delete_final_note)
delete_insn (insn);
return 1;
}
return 0;
}
static int
duplicate_loop_exit_test (loop_start)
rtx loop_start;
{
rtx insn, set, reg, p, link;
rtx copy = 0, first_copy = 0;
int num_insns = 0;
rtx exitcode = NEXT_INSN (JUMP_LABEL (next_nonnote_insn (loop_start)));
rtx lastexit;
int max_reg = max_reg_num ();
rtx *reg_map = 0;
for (insn = exitcode;
insn
&& ! (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END);
insn = NEXT_INSN (insn))
{
switch (GET_CODE (insn))
{
case CODE_LABEL:
case CALL_INSN:
return 0;
case NOTE:
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
return 0;
if (optimize < 2
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
return 0;
break;
case JUMP_INSN:
case INSN:
while ((p = find_reg_note (insn, REG_WAS_0, NULL_RTX)) != 0)
remove_note (insn, p);
if (++num_insns > 20
|| find_reg_note (insn, REG_RETVAL, NULL_RTX)
|| find_reg_note (insn, REG_LIBCALL, NULL_RTX)
|| asm_noperands (PATTERN (insn)) > 0)
return 0;
break;
default:
break;
}
}
if (insn == 0)
return 0;
lastexit = insn;
for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == INSN
&& (set = single_set (insn)) != 0
&& ((reg = SET_DEST (set), GET_CODE (reg) == REG)
|| (GET_CODE (reg) == SUBREG
&& (reg = SUBREG_REG (reg), GET_CODE (reg) == REG)))
&& REGNO (reg) >= FIRST_PSEUDO_REGISTER
&& REGNO_FIRST_UID (REGNO (reg)) == INSN_UID (insn))
{
for (p = NEXT_INSN (insn); p != lastexit; p = NEXT_INSN (p))
if (REGNO_LAST_UID (REGNO (reg)) == INSN_UID (p))
break;
if (p != lastexit)
{
if (reg_map == 0)
{
reg_map = (rtx *) alloca (max_reg * sizeof (rtx));
bzero ((char *) reg_map, max_reg * sizeof (rtx));
}
REG_LOOP_TEST_P (reg) = 1;
reg_map[REGNO (reg)] = gen_reg_rtx (GET_MODE (reg));
}
}
for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))
{
switch (GET_CODE (insn))
{
case BARRIER:
copy = emit_barrier_before (loop_start);
break;
case NOTE:
if (NOTE_LINE_NUMBER (insn) >= 0)
{
copy = emit_note_before (NOTE_LINE_NUMBER (insn), loop_start);
NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
}
break;
case INSN:
copy = emit_insn_before (copy_rtx (PATTERN (insn)), loop_start);
if (reg_map)
replace_regs (PATTERN (copy), reg_map, max_reg, 1);
mark_jump_label (PATTERN (copy), copy, 0);
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) != REG_LABEL)
REG_NOTES (copy)
= copy_rtx (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
XEXP (link, 0),
REG_NOTES (copy)));
if (reg_map && REG_NOTES (copy))
replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
break;
case JUMP_INSN:
copy = emit_jump_insn_before (copy_rtx (PATTERN (insn)), loop_start);
if (reg_map)
replace_regs (PATTERN (copy), reg_map, max_reg, 1);
mark_jump_label (PATTERN (copy), copy, 0);
if (REG_NOTES (insn))
{
REG_NOTES (copy) = copy_rtx (REG_NOTES (insn));
if (reg_map)
replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
}
if (INSN_UID (copy) < max_jump_chain && JUMP_LABEL (copy)
&& simplejump_p (copy))
{
jump_chain[INSN_UID (copy)]
= jump_chain[INSN_UID (JUMP_LABEL (copy))];
jump_chain[INSN_UID (JUMP_LABEL (copy))] = copy;
}
break;
default:
abort ();
}
if (! first_copy)
first_copy = copy;
}
if (! copy || GET_CODE (copy) != BARRIER)
{
copy = emit_jump_insn_before (gen_jump (get_label_after (insn)),
loop_start);
if (! first_copy)
first_copy = copy;
mark_jump_label (PATTERN (copy), copy, 0);
if (INSN_UID (copy) < max_jump_chain
&& INSN_UID (JUMP_LABEL (copy)) < max_jump_chain)
{
jump_chain[INSN_UID (copy)]
= jump_chain[INSN_UID (JUMP_LABEL (copy))];
jump_chain[INSN_UID (JUMP_LABEL (copy))] = copy;
}
emit_barrier_before (loop_start);
}
reg_scan_update (first_copy, copy, max_reg);
emit_note_before (NOTE_INSN_LOOP_VTOP, exitcode);
delete_insn (next_nonnote_insn (loop_start));
return 1;
}
rtx
squeeze_notes (start, end)
rtx start, end;
{
rtx insn;
rtx next;
for (insn = start; insn != end; insn = next)
{
next = NEXT_INSN (insn);
if (GET_CODE (insn) == NOTE
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_VTOP
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
{
if (insn == start)
start = next;
else
{
rtx prev = PREV_INSN (insn);
PREV_INSN (insn) = PREV_INSN (start);
NEXT_INSN (insn) = start;
NEXT_INSN (PREV_INSN (insn)) = insn;
PREV_INSN (NEXT_INSN (insn)) = insn;
NEXT_INSN (prev) = next;
PREV_INSN (next) = prev;
}
}
}
return start;
}
static void
find_cross_jump (e1, e2, minimum, f1, f2)
rtx e1, e2;
int minimum;
rtx *f1, *f2;
{
register rtx i1 = e1, i2 = e2;
register rtx p1, p2;
int lose = 0;
rtx last1 = 0, last2 = 0;
rtx afterlast1 = 0, afterlast2 = 0;
*f1 = 0;
*f2 = 0;
while (1)
{
i1 = prev_nonnote_insn (i1);
i2 = PREV_INSN (i2);
while (i2 && (GET_CODE (i2) == NOTE || GET_CODE (i2) == CODE_LABEL))
i2 = PREV_INSN (i2);
if (i1 == 0)
break;
if (i2 == e1 || i1 == e2)
break;
if (GET_CODE (i1) == CODE_LABEL)
{
--minimum;
break;
}
if (i2 == 0 || GET_CODE (i1) != GET_CODE (i2))
break;
if (flag_exceptions
&& (asynchronous_exceptions || GET_CODE (i1) == CALL_INSN)
&& !in_same_eh_region (i1, i2))
break;
p1 = PATTERN (i1);
p2 = PATTERN (i2);
if (GET_CODE (i1) == CALL_INSN
&& ! rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
CALL_INSN_FUNCTION_USAGE (i2)))
lose = 1;
#ifdef STACK_REGS
if (!lose && cross_jump_death_matters && stack_regs_mentioned (i1))
{
rtx note;
HARD_REG_SET i1_regset, i2_regset;
CLEAR_HARD_REG_SET (i1_regset);
CLEAR_HARD_REG_SET (i2_regset);
for (note = REG_NOTES (i1); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_DEAD
&& STACK_REG_P (XEXP (note, 0)))
SET_HARD_REG_BIT (i1_regset, REGNO (XEXP (note, 0)));
for (note = REG_NOTES (i2); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_DEAD
&& STACK_REG_P (XEXP (note, 0)))
SET_HARD_REG_BIT (i2_regset, REGNO (XEXP (note, 0)));
GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done);
lose = 1;
done:
;
}
#endif
if (GET_CODE (p1) == ASM_INPUT || GET_CODE (p2) == ASM_INPUT
|| (GET_CODE (p1) == ASM_OPERANDS && MEM_VOLATILE_P (p1))
|| (GET_CODE (p2) == ASM_OPERANDS && MEM_VOLATILE_P (p2)))
lose = 1;
if (lose || GET_CODE (p1) != GET_CODE (p2)
|| ! rtx_renumbered_equal_p (p1, p2))
{
rtx equiv1;
rtx equiv2;
if (!lose && GET_CODE (p1) == GET_CODE (p2)
&& ((equiv1 = find_reg_note (i1, REG_EQUAL, NULL_RTX)) != 0
|| (equiv1 = find_reg_note (i1, REG_EQUIV, NULL_RTX)) != 0)
&& ((equiv2 = find_reg_note (i2, REG_EQUAL, NULL_RTX)) != 0
|| (equiv2 = find_reg_note (i2, REG_EQUIV, NULL_RTX)) != 0)
&& CONSTANT_P (XEXP (equiv1, 0))
&& rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))
{
rtx s1 = single_set (i1);
rtx s2 = single_set (i2);
if (s1 != 0 && s2 != 0
&& rtx_renumbered_equal_p (SET_DEST (s1), SET_DEST (s2)))
{
validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1);
validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1);
if (! rtx_renumbered_equal_p (p1, p2))
cancel_changes (0);
else if (apply_change_group ())
goto win;
}
}
#ifdef HAVE_cc0
if (sets_cc0_p (p1) || sets_cc0_p (p2))
last1 = afterlast1, last2 = afterlast2, ++minimum;
#endif
if (GET_CODE (i1) == JUMP_INSN
&& JUMP_LABEL (i1)
&& prev_real_insn (JUMP_LABEL (i1)) == e1)
--minimum;
break;
}
win:
if (GET_CODE (p1) != USE && GET_CODE (p1) != CLOBBER)
{
afterlast1 = last1, afterlast2 = last2;
last1 = i1, last2 = i2, --minimum;
}
}
if (minimum <= 0 && last1 != 0 && last1 != e1)
*f1 = last1, *f2 = last2;
}
static void
do_cross_jump (insn, newjpos, newlpos)
rtx insn, newjpos, newlpos;
{
register rtx label = get_label_before (newlpos);
if (GET_CODE (PATTERN (insn)) == RETURN)
{
delete_from_jump_chain (insn);
PATTERN (insn) = gen_jump (label);
INSN_CODE (insn) = -1;
JUMP_LABEL (insn) = label;
LABEL_NUSES (label)++;
if (INSN_UID (label) < max_jump_chain
&& INSN_UID (insn) < max_jump_chain)
{
jump_chain[INSN_UID (insn)] = jump_chain[INSN_UID (label)];
jump_chain[INSN_UID (label)] = insn;
}
}
else
redirect_jump (insn, label);
while (newjpos != insn)
{
rtx lnote;
for (lnote = REG_NOTES (newlpos); lnote; lnote = XEXP (lnote, 1))
if ((REG_NOTE_KIND (lnote) == REG_EQUAL
|| REG_NOTE_KIND (lnote) == REG_EQUIV)
&& ! find_reg_note (newjpos, REG_EQUAL, XEXP (lnote, 0))
&& ! find_reg_note (newjpos, REG_EQUIV, XEXP (lnote, 0)))
remove_note (newlpos, lnote);
delete_insn (newjpos);
newjpos = next_real_insn (newjpos);
newlpos = next_real_insn (newlpos);
}
}
rtx
get_label_before (insn)
rtx insn;
{
rtx label;
label = prev_nonnote_insn (insn);
if (label == 0 || GET_CODE (label) != CODE_LABEL)
{
rtx prev = PREV_INSN (insn);
label = gen_label_rtx ();
emit_label_after (label, prev);
LABEL_NUSES (label) = 0;
}
return label;
}
rtx
get_label_after (insn)
rtx insn;
{
rtx label;
label = next_nonnote_insn (insn);
if (label == 0 || GET_CODE (label) != CODE_LABEL)
{
label = gen_label_rtx ();
emit_label_after (label, insn);
LABEL_NUSES (label) = 0;
}
return label;
}
static int
jump_back_p (insn, target)
rtx insn, target;
{
rtx cinsn, ctarget;
enum rtx_code codei, codet;
if (simplejump_p (insn) || ! condjump_p (insn)
|| simplejump_p (target)
|| target != prev_real_insn (JUMP_LABEL (insn)))
return 0;
cinsn = XEXP (SET_SRC (PATTERN (insn)), 0);
ctarget = XEXP (SET_SRC (PATTERN (target)), 0);
codei = GET_CODE (cinsn);
codet = GET_CODE (ctarget);
if (XEXP (SET_SRC (PATTERN (insn)), 1) == pc_rtx)
{
if (! can_reverse_comparison_p (cinsn, insn))
return 0;
codei = reverse_condition (codei);
}
if (XEXP (SET_SRC (PATTERN (target)), 2) == pc_rtx)
{
if (! can_reverse_comparison_p (ctarget, target))
return 0;
codet = reverse_condition (codet);
}
return (codei == codet
&& rtx_renumbered_equal_p (XEXP (cinsn, 0), XEXP (ctarget, 0))
&& rtx_renumbered_equal_p (XEXP (cinsn, 1), XEXP (ctarget, 1)));
}
int
can_reverse_comparison_p (comparison, insn)
rtx comparison;
rtx insn;
{
rtx arg0;
if (GET_RTX_CLASS (GET_CODE (comparison)) != '<')
return 0;
if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| flag_fast_math
|| GET_CODE (comparison) == NE
|| GET_CODE (comparison) == EQ)
return 1;
arg0 = XEXP (comparison, 0);
if ((GET_CODE (arg0) == REG && GET_MODE_CLASS (GET_MODE (arg0)) == MODE_CC)
#ifdef HAVE_cc0
|| arg0 == cc0_rtx
#endif
)
{
rtx prev = prev_nonnote_insn (insn);
rtx set;
if (prev == 0)
return 0;
set = single_set (prev);
if (set == 0 || SET_DEST (set) != arg0)
return 0;
arg0 = SET_SRC (set);
if (GET_CODE (arg0) == COMPARE)
arg0 = XEXP (arg0, 0);
}
return (GET_CODE (arg0) == CONST_INT
|| (GET_MODE (arg0) != VOIDmode
&& GET_MODE_CLASS (GET_MODE (arg0)) != MODE_CC
&& GET_MODE_CLASS (GET_MODE (arg0)) != MODE_FLOAT));
}
enum rtx_code
reverse_condition (code)
enum rtx_code code;
{
switch (code)
{
case EQ:
return NE;
case NE:
return EQ;
case GT:
return LE;
case GE:
return LT;
case LT:
return GE;
case LE:
return GT;
case GTU:
return LEU;
case GEU:
return LTU;
case LTU:
return GEU;
case LEU:
return GTU;
default:
abort ();
return UNKNOWN;
}
}
enum rtx_code
swap_condition (code)
enum rtx_code code;
{
switch (code)
{
case EQ:
case NE:
return code;
case GT:
return LT;
case GE:
return LE;
case LT:
return GT;
case LE:
return GE;
case GTU:
return LTU;
case GEU:
return LEU;
case LTU:
return GTU;
case LEU:
return GEU;
default:
abort ();
return UNKNOWN;
}
}
enum rtx_code
unsigned_condition (code)
enum rtx_code code;
{
switch (code)
{
case EQ:
case NE:
case GTU:
case GEU:
case LTU:
case LEU:
return code;
case GT:
return GTU;
case GE:
return GEU;
case LT:
return LTU;
case LE:
return LEU;
default:
abort ();
}
}
enum rtx_code
signed_condition (code)
enum rtx_code code;
{
switch (code)
{
case EQ:
case NE:
case GT:
case GE:
case LT:
case LE:
return code;
case GTU:
return GT;
case GEU:
return GE;
case LTU:
return LT;
case LEU:
return LE;
default:
abort ();
}
}
int
comparison_dominates_p (code1, code2)
enum rtx_code code1, code2;
{
if (code1 == code2)
return 1;
switch (code1)
{
case EQ:
if (code2 == LE || code2 == LEU || code2 == GE || code2 == GEU)
return 1;
break;
case LT:
if (code2 == LE || code2 == NE)
return 1;
break;
case GT:
if (code2 == GE || code2 == NE)
return 1;
break;
case LTU:
if (code2 == LEU || code2 == NE)
return 1;
break;
case GTU:
if (code2 == GEU || code2 == NE)
return 1;
break;
default:
break;
}
return 0;
}
int
simplejump_p (insn)
rtx insn;
{
return (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (insn))) == PC
&& GET_CODE (SET_SRC (PATTERN (insn))) == LABEL_REF);
}
int
condjump_p (insn)
rtx insn;
{
register rtx x = PATTERN (insn);
if (GET_CODE (x) != SET)
return 0;
if (GET_CODE (SET_DEST (x)) != PC)
return 0;
if (GET_CODE (SET_SRC (x)) == LABEL_REF)
return 1;
if (GET_CODE (SET_SRC (x)) != IF_THEN_ELSE)
return 0;
if (XEXP (SET_SRC (x), 2) == pc_rtx
&& (GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF
|| GET_CODE (XEXP (SET_SRC (x), 1)) == RETURN))
return 1;
if (XEXP (SET_SRC (x), 1) == pc_rtx
&& (GET_CODE (XEXP (SET_SRC (x), 2)) == LABEL_REF
|| GET_CODE (XEXP (SET_SRC (x), 2)) == RETURN))
return 1;
return 0;
}
int
condjump_in_parallel_p (insn)
rtx insn;
{
register rtx x = PATTERN (insn);
if (GET_CODE (x) != PARALLEL)
return 0;
else
x = XVECEXP (x, 0, 0);
if (GET_CODE (x) != SET)
return 0;
if (GET_CODE (SET_DEST (x)) != PC)
return 0;
if (GET_CODE (SET_SRC (x)) == LABEL_REF)
return 1;
if (GET_CODE (SET_SRC (x)) != IF_THEN_ELSE)
return 0;
if (XEXP (SET_SRC (x), 2) == pc_rtx
&& (GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF
|| GET_CODE (XEXP (SET_SRC (x), 1)) == RETURN))
return 1;
if (XEXP (SET_SRC (x), 1) == pc_rtx
&& (GET_CODE (XEXP (SET_SRC (x), 2)) == LABEL_REF
|| GET_CODE (XEXP (SET_SRC (x), 2)) == RETURN))
return 1;
return 0;
}
rtx
condjump_label (insn)
rtx insn;
{
register rtx x = PATTERN (insn);
if (GET_CODE (x) == PARALLEL)
x = XVECEXP (x, 0, 0);
if (GET_CODE (x) != SET)
return NULL_RTX;
if (GET_CODE (SET_DEST (x)) != PC)
return NULL_RTX;
x = SET_SRC (x);
if (GET_CODE (x) == LABEL_REF)
return x;
if (GET_CODE (x) != IF_THEN_ELSE)
return NULL_RTX;
if (XEXP (x, 2) == pc_rtx && GET_CODE (XEXP (x, 1)) == LABEL_REF)
return XEXP (x, 1);
if (XEXP (x, 1) == pc_rtx && GET_CODE (XEXP (x, 2)) == LABEL_REF)
return XEXP (x, 2);
return NULL_RTX;
}
static int
returnjump_p_1 (loc, data)
rtx *loc;
void *data ATTRIBUTE_UNUSED;
{
rtx x = *loc;
return GET_CODE (x) == RETURN;
}
int
returnjump_p (insn)
rtx insn;
{
return for_each_rtx (&PATTERN (insn), returnjump_p_1, NULL);
}
#ifdef HAVE_cc0
int
sets_cc0_p (x)
rtx x ATTRIBUTE_UNUSED;
{
if (GET_CODE (x) == SET && SET_DEST (x) == cc0_rtx)
return 1;
if (GET_CODE (x) == PARALLEL)
{
int i;
int sets_cc0 = 0;
int other_things = 0;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
if (GET_CODE (XVECEXP (x, 0, i)) == SET
&& SET_DEST (XVECEXP (x, 0, i)) == cc0_rtx)
sets_cc0 = 1;
else if (GET_CODE (XVECEXP (x, 0, i)) == SET)
other_things = 1;
}
return ! sets_cc0 ? 0 : other_things ? -1 : 1;
}
return 0;
}
#endif
rtx
follow_jumps (label)
rtx label;
{
register rtx insn;
register rtx next;
register rtx value = label;
register int depth;
for (depth = 0;
(depth < 10
&& (insn = next_active_insn (value)) != 0
&& GET_CODE (insn) == JUMP_INSN
&& ((JUMP_LABEL (insn) != 0 && simplejump_p (insn))
|| GET_CODE (PATTERN (insn)) == RETURN)
&& (next = NEXT_INSN (insn))
&& GET_CODE (next) == BARRIER);
depth++)
{
rtx tem;
if (!reload_completed)
for (tem = value; tem != insn; tem = NEXT_INSN (tem))
if (GET_CODE (tem) == NOTE
&& (NOTE_LINE_NUMBER (tem) == NOTE_INSN_LOOP_BEG
|| (flag_test_coverage && NOTE_LINE_NUMBER (tem) > 0)))
return value;
if (JUMP_LABEL (insn) == label)
return label;
tem = next_active_insn (JUMP_LABEL (insn));
if (tem && (GET_CODE (PATTERN (tem)) == ADDR_VEC
|| GET_CODE (PATTERN (tem)) == ADDR_DIFF_VEC))
break;
value = JUMP_LABEL (insn);
}
if (depth == 10)
return label;
return value;
}
static int
tension_vector_labels (x, idx)
register rtx x;
register int idx;
{
int changed = 0;
register int i;
for (i = XVECLEN (x, idx) - 1; i >= 0; i--)
{
register rtx olabel = XEXP (XVECEXP (x, idx, i), 0);
register rtx nlabel = follow_jumps (olabel);
if (nlabel && nlabel != olabel)
{
XEXP (XVECEXP (x, idx, i), 0) = nlabel;
++LABEL_NUSES (nlabel);
if (--LABEL_NUSES (olabel) == 0)
delete_insn (olabel);
changed = 1;
}
}
return changed;
}
static void
mark_jump_label (x, insn, cross_jump)
register rtx x;
rtx insn;
int cross_jump;
{
register RTX_CODE code = GET_CODE (x);
register int i;
register char *fmt;
switch (code)
{
case PC:
case CC0:
case REG:
case SUBREG:
case CONST_INT:
case SYMBOL_REF:
case CONST_DOUBLE:
case CLOBBER:
case CALL:
return;
case MEM:
if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
mark_jump_label (get_pool_constant (XEXP (x, 0)), insn, cross_jump);
break;
case LABEL_REF:
{
rtx label = XEXP (x, 0);
rtx olabel = label;
rtx note;
rtx next;
if (GET_CODE (label) != CODE_LABEL)
abort ();
if (LABEL_REF_NONLOCAL_P (x))
break;
for (next = NEXT_INSN (label); next; next = NEXT_INSN (next))
{
if (GET_CODE (next) == CODE_LABEL)
label = next;
else if (cross_jump && GET_CODE (next) == INSN
&& (GET_CODE (PATTERN (next)) == USE
|| GET_CODE (PATTERN (next)) == CLOBBER))
continue;
else if (GET_CODE (next) != NOTE)
break;
else if (! cross_jump
&& (NOTE_LINE_NUMBER (next) == NOTE_INSN_LOOP_BEG
|| NOTE_LINE_NUMBER (next) == NOTE_INSN_FUNCTION_END
|| (flag_test_coverage && NOTE_LINE_NUMBER (next) > 0)))
break;
}
XEXP (x, 0) = label;
if (! insn || ! INSN_DELETED_P (insn))
++LABEL_NUSES (label);
if (insn)
{
if (GET_CODE (insn) == JUMP_INSN)
JUMP_LABEL (insn) = label;
else if (label != olabel
&& (note = find_reg_note (insn, REG_LABEL, olabel)) != 0)
XEXP (note, 0) = label;
else if (! find_reg_note (insn, REG_LABEL, label))
{
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, label,
REG_NOTES (insn));
}
}
return;
}
case ADDR_VEC:
case ADDR_DIFF_VEC:
if (! INSN_DELETED_P (insn))
{
int eltnum = code == ADDR_DIFF_VEC ? 1 : 0;
for (i = 0; i < XVECLEN (x, eltnum); i++)
mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, cross_jump);
}
return;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
mark_jump_label (XEXP (x, i), insn, cross_jump);
else if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
mark_jump_label (XVECEXP (x, i, j), insn, cross_jump);
}
}
}
void
delete_jump (insn)
rtx insn;
{
register rtx set = single_set (insn);
if (set && GET_CODE (SET_DEST (set)) == PC)
delete_computation (insn);
}
static void
delete_computation (insn)
rtx insn;
{
rtx note, next;
#ifdef HAVE_cc0
if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
{
rtx prev = prev_nonnote_insn (insn);
if (prev && GET_CODE (prev) == INSN
&& sets_cc0_p (PATTERN (prev)))
{
if (sets_cc0_p (PATTERN (prev)) > 0
&& !FIND_REG_INC_NOTE (prev, NULL_RTX))
delete_computation (prev);
else
REG_NOTES (prev) = gen_rtx_EXPR_LIST (REG_UNUSED,
cc0_rtx, REG_NOTES (prev));
}
}
#endif
#ifdef INSN_SCHEDULING
if (reload_completed && flag_schedule_insns_after_reload)
{
delete_insn (insn);
return;
}
#endif
for (note = REG_NOTES (insn); note; note = next)
{
rtx our_prev;
next = XEXP (note, 1);
if (REG_NOTE_KIND (note) != REG_DEAD
|| GET_CODE (XEXP (note, 0)) != REG)
continue;
for (our_prev = prev_nonnote_insn (insn);
our_prev && GET_CODE (our_prev) == INSN;
our_prev = prev_nonnote_insn (our_prev))
{
if (GET_CODE (PATTERN (our_prev)) == SEQUENCE)
break;
if (GET_CODE (PATTERN (our_prev)) == USE
&& GET_CODE (XEXP (PATTERN (our_prev), 0)) == INSN)
break;
if (reg_set_p (XEXP (note, 0), PATTERN (our_prev)))
{
if (FIND_REG_INC_NOTE (our_prev, NULL_RTX))
break;
if (GET_CODE (PATTERN (our_prev)) == PARALLEL)
{
int i;
for (i = 0; i < XVECLEN (PATTERN (our_prev), 0); i++)
{
rtx part = XVECEXP (PATTERN (our_prev), 0, i);
if (GET_CODE (part) == SET
&& SET_DEST (part) != XEXP (note, 0))
break;
}
if (i == XVECLEN (PATTERN (our_prev), 0))
delete_computation (our_prev);
}
else if (GET_CODE (PATTERN (our_prev)) == SET
&& SET_DEST (PATTERN (our_prev)) == XEXP (note, 0))
delete_computation (our_prev);
break;
}
if (reg_overlap_mentioned_p (XEXP (note, 0),
PATTERN (our_prev)))
{
XEXP (note, 1) = REG_NOTES (our_prev);
REG_NOTES (our_prev) = note;
break;
}
}
}
delete_insn (insn);
}
rtx
delete_insn (insn)
register rtx insn;
{
register rtx next = NEXT_INSN (insn);
register rtx prev = PREV_INSN (insn);
register int was_code_label = (GET_CODE (insn) == CODE_LABEL);
register int dont_really_delete = 0;
while (next && INSN_DELETED_P (next))
next = NEXT_INSN (next);
if (INSN_DELETED_P (insn))
return next;
if (was_code_label)
remove_node_from_expr_list (insn, &nonlocal_goto_handler_labels);
if (was_code_label && LABEL_NAME (insn) != 0
&& optimize && ! dont_really_delete)
{
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED_LABEL;
NOTE_SOURCE_FILE (insn) = 0;
dont_really_delete = 1;
}
else
INSN_DELETED_P (insn) = 1;
if (simplejump_p (insn))
delete_from_jump_chain (insn);
if (next != 0 && GET_CODE (next) == BARRIER)
{
INSN_DELETED_P (next) = 1;
next = NEXT_INSN (next);
}
if (optimize && ! dont_really_delete)
{
if (prev)
{
NEXT_INSN (prev) = next;
if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
NEXT_INSN (XVECEXP (PATTERN (prev), 0,
XVECLEN (PATTERN (prev), 0) - 1)) = next;
}
if (next)
{
PREV_INSN (next) = prev;
if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE)
PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev;
}
if (prev && NEXT_INSN (prev) == 0)
set_last_insn (prev);
}
if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn))
{
rtx lab = JUMP_LABEL (insn), lab_next;
if (--LABEL_NUSES (lab) == 0)
{
delete_insn (lab);
while (next && INSN_DELETED_P (next))
next = NEXT_INSN (next);
return next;
}
else if ((lab_next = next_nonnote_insn (lab)) != NULL
&& GET_CODE (lab_next) == JUMP_INSN
&& (GET_CODE (PATTERN (lab_next)) == ADDR_VEC
|| GET_CODE (PATTERN (lab_next)) == ADDR_DIFF_VEC))
{
delete_insn (lab_next);
}
}
if (GET_CODE (insn) == JUMP_INSN
&& (GET_CODE (PATTERN (insn)) == ADDR_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
{
rtx pat = PATTERN (insn);
int i, diff_vec_p = GET_CODE (pat) == ADDR_DIFF_VEC;
int len = XVECLEN (pat, diff_vec_p);
for (i = 0; i < len; i++)
if (--LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0)) == 0)
delete_insn (XEXP (XVECEXP (pat, diff_vec_p, i), 0));
while (next && INSN_DELETED_P (next))
next = NEXT_INSN (next);
return next;
}
while (prev && (INSN_DELETED_P (prev) || GET_CODE (prev) == NOTE))
prev = PREV_INSN (prev);
if (was_code_label
&& NEXT_INSN (insn) != 0
&& GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
&& (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC
|| GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC))
next = delete_insn (NEXT_INSN (insn));
if (was_code_label && prev && GET_CODE (prev) == BARRIER)
{
register RTX_CODE code;
while (next != 0
&& (GET_RTX_CLASS (code = GET_CODE (next)) == 'i'
|| code == NOTE || code == BARRIER
|| (code == CODE_LABEL && INSN_DELETED_P (next))))
{
if (code == NOTE
&& NOTE_LINE_NUMBER (next) != NOTE_INSN_FUNCTION_END)
next = NEXT_INSN (next);
else if (code == CODE_LABEL && INSN_DELETED_P (next))
next = NEXT_INSN (next);
else
next = delete_insn (next);
}
}
return next;
}
rtx
next_nondeleted_insn (insn)
rtx insn;
{
while (INSN_DELETED_P (insn))
insn = NEXT_INSN (insn);
return insn;
}
void
delete_for_peephole (from, to)
register rtx from, to;
{
register rtx insn = from;
while (1)
{
register rtx next = NEXT_INSN (insn);
register rtx prev = PREV_INSN (insn);
if (GET_CODE (insn) != NOTE)
{
INSN_DELETED_P (insn) = 1;
if (prev)
NEXT_INSN (prev) = next;
if (next)
PREV_INSN (next) = prev;
}
if (insn == to)
break;
insn = next;
}
}
int
invert_jump (jump, nlabel)
rtx jump, nlabel;
{
if (! invert_exp (PATTERN (jump), jump))
return 0;
if (redirect_jump (jump, nlabel))
{
if (flag_branch_probabilities)
{
rtx note = find_reg_note (jump, REG_BR_PROB, 0);
if (note && XINT (XEXP (note, 0), 0) >= 0)
XINT (XEXP (note, 0), 0) = REG_BR_PROB_BASE - XINT (XEXP (note, 0), 0);
}
return 1;
}
if (! invert_exp (PATTERN (jump), jump))
abort ();
return 0;
}
int
invert_exp (x, insn)
rtx x;
rtx insn;
{
register RTX_CODE code;
register int i;
register char *fmt;
code = GET_CODE (x);
if (code == IF_THEN_ELSE)
{
register rtx comp = XEXP (x, 0);
register rtx tem;
if (can_reverse_comparison_p (comp, insn)
&& validate_change (insn, &XEXP (x, 0),
gen_rtx_fmt_ee (reverse_condition (GET_CODE (comp)),
GET_MODE (comp), XEXP (comp, 0),
XEXP (comp, 1)), 0))
return 1;
tem = XEXP (x, 1);
validate_change (insn, &XEXP (x, 1), XEXP (x, 2), 1);
validate_change (insn, &XEXP (x, 2), tem, 1);
return apply_change_group ();
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
if (! invert_exp (XEXP (x, i), insn))
return 0;
if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
if (!invert_exp (XVECEXP (x, i, j), insn))
return 0;
}
}
return 1;
}
int
redirect_jump (jump, nlabel)
rtx jump, nlabel;
{
register rtx olabel = JUMP_LABEL (jump);
if (nlabel == olabel)
return 1;
if (! redirect_exp (&PATTERN (jump), olabel, nlabel, jump))
return 0;
if (jump_chain && (simplejump_p (jump)
|| GET_CODE (PATTERN (jump)) == RETURN))
{
int label_index = nlabel ? INSN_UID (nlabel) : 0;
delete_from_jump_chain (jump);
if (label_index < max_jump_chain
&& INSN_UID (jump) < max_jump_chain)
{
jump_chain[INSN_UID (jump)] = jump_chain[label_index];
jump_chain[label_index] = jump;
}
}
JUMP_LABEL (jump) = nlabel;
if (nlabel)
++LABEL_NUSES (nlabel);
if (olabel && --LABEL_NUSES (olabel) == 0)
delete_insn (olabel);
return 1;
}
static void
delete_from_jump_chain (jump)
rtx jump;
{
int index;
rtx olabel = JUMP_LABEL (jump);
if (jump_chain && olabel != 0
&& INSN_UID (olabel) < max_jump_chain
&& simplejump_p (jump))
index = INSN_UID (olabel);
else if (jump_chain && GET_CODE (PATTERN (jump)) == RETURN)
index = 0;
else return;
if (jump_chain[index] == jump)
jump_chain[index] = jump_chain[INSN_UID (jump)];
else
{
rtx insn;
for (insn = jump_chain[index];
insn != 0;
insn = jump_chain[INSN_UID (insn)])
if (jump_chain[INSN_UID (insn)] == jump)
{
jump_chain[INSN_UID (insn)] = jump_chain[INSN_UID (jump)];
break;
}
}
}
int
redirect_exp (loc, olabel, nlabel, insn)
rtx *loc;
rtx olabel, nlabel;
rtx insn;
{
register rtx x = *loc;
register RTX_CODE code = GET_CODE (x);
register int i;
register char *fmt;
if (code == LABEL_REF)
{
if (XEXP (x, 0) == olabel)
{
if (nlabel)
XEXP (x, 0) = nlabel;
else
return validate_change (insn, loc, gen_rtx_RETURN (VOIDmode), 0);
return 1;
}
}
else if (code == RETURN && olabel == 0)
{
x = gen_rtx_LABEL_REF (VOIDmode, nlabel);
if (loc == &PATTERN (insn))
x = gen_rtx_SET (VOIDmode, pc_rtx, x);
return validate_change (insn, loc, x, 0);
}
if (code == SET && nlabel == 0 && SET_DEST (x) == pc_rtx
&& GET_CODE (SET_SRC (x)) == LABEL_REF
&& XEXP (SET_SRC (x), 0) == olabel)
return validate_change (insn, loc, gen_rtx_RETURN (VOIDmode), 0);
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
if (! redirect_exp (&XEXP (x, i), olabel, nlabel, insn))
return 0;
if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
if (! redirect_exp (&XVECEXP (x, i, j), olabel, nlabel, insn))
return 0;
}
}
return 1;
}
static void
redirect_tablejump (jump, nlabel)
rtx jump, nlabel;
{
register rtx olabel = JUMP_LABEL (jump);
if (jump_chain && INSN_UID (nlabel) < max_jump_chain
&& INSN_UID (jump) < max_jump_chain)
{
jump_chain[INSN_UID (jump)] = jump_chain[INSN_UID (nlabel)];
jump_chain[INSN_UID (nlabel)] = jump;
}
PATTERN (jump) = gen_jump (nlabel);
JUMP_LABEL (jump) = nlabel;
++LABEL_NUSES (nlabel);
INSN_CODE (jump) = -1;
if (--LABEL_NUSES (olabel) == 0)
{
delete_labelref_insn (jump, olabel, 0);
delete_insn (olabel);
}
}
static int
delete_labelref_insn (insn, label, delete_this)
rtx insn, label;
int delete_this;
{
int deleted = 0;
rtx link;
if (GET_CODE (insn) != NOTE
&& reg_mentioned_p (label, PATTERN (insn)))
{
if (delete_this)
{
delete_insn (insn);
deleted = 1;
}
else
return 1;
}
for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
if (delete_labelref_insn (XEXP (link, 0), label, 1))
{
if (delete_this)
{
delete_insn (insn);
deleted = 1;
}
else
return 1;
}
return deleted;
}
int
rtx_renumbered_equal_p (x, y)
rtx x, y;
{
register int i;
register RTX_CODE code = GET_CODE (x);
register char *fmt;
if (x == y)
return 1;
if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
&& (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG
&& GET_CODE (SUBREG_REG (y)) == REG)))
{
int reg_x = -1, reg_y = -1;
int word_x = 0, word_y = 0;
if (GET_MODE (x) != GET_MODE (y))
return 0;
if (reg_renumber == 0)
return rtx_equal_p (x, y);
if (code == SUBREG)
{
reg_x = REGNO (SUBREG_REG (x));
word_x = SUBREG_WORD (x);
if (reg_renumber[reg_x] >= 0)
{
reg_x = reg_renumber[reg_x] + word_x;
word_x = 0;
}
}
else
{
reg_x = REGNO (x);
if (reg_renumber[reg_x] >= 0)
reg_x = reg_renumber[reg_x];
}
if (GET_CODE (y) == SUBREG)
{
reg_y = REGNO (SUBREG_REG (y));
word_y = SUBREG_WORD (y);
if (reg_renumber[reg_y] >= 0)
{
reg_y = reg_renumber[reg_y];
word_y = 0;
}
}
else
{
reg_y = REGNO (y);
if (reg_renumber[reg_y] >= 0)
reg_y = reg_renumber[reg_y];
}
return reg_x >= 0 && reg_x == reg_y && word_x == word_y;
}
if (code != GET_CODE (y))
return 0;
switch (code)
{
case PC:
case CC0:
case ADDR_VEC:
case ADDR_DIFF_VEC:
return 0;
case CONST_INT:
return INTVAL (x) == INTVAL (y);
case LABEL_REF:
if (LABEL_REF_NONLOCAL_P (x) || LABEL_REF_NONLOCAL_P (y))
return XEXP (x, 0) == XEXP (y, 0);
return (next_real_insn (XEXP (x, 0))
== next_real_insn (XEXP (y, 0)));
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
case CODE_LABEL:
return 0;
default:
break;
}
if (GET_MODE (x) != GET_MODE (y))
return 0;
if ((code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
&& code != PLUS)
return ((rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0))
&& rtx_renumbered_equal_p (XEXP (x, 1), XEXP (y, 1)))
|| (rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 1))
&& rtx_renumbered_equal_p (XEXP (x, 1), XEXP (y, 0))));
else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
return (rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0))
&& rtx_renumbered_equal_p (XEXP (x, 1), XEXP (y, 1)));
else if (GET_RTX_CLASS (code) == '1')
return rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0));
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
register int j;
switch (fmt[i])
{
case 'w':
if (XWINT (x, i) != XWINT (y, i))
return 0;
break;
case 'i':
if (XINT (x, i) != XINT (y, i))
return 0;
break;
case 's':
if (strcmp (XSTR (x, i), XSTR (y, i)))
return 0;
break;
case 'e':
if (! rtx_renumbered_equal_p (XEXP (x, i), XEXP (y, i)))
return 0;
break;
case 'u':
if (XEXP (x, i) != XEXP (y, i))
return 0;
case '0':
break;
case 'E':
if (XVECLEN (x, i) != XVECLEN (y, i))
return 0;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (!rtx_renumbered_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)))
return 0;
break;
default:
abort ();
}
}
return 1;
}
int
true_regnum (x)
rtx x;
{
if (GET_CODE (x) == REG)
{
if (REGNO (x) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (x)] >= 0)
return reg_renumber[REGNO (x)];
return REGNO (x);
}
if (GET_CODE (x) == SUBREG)
{
int base = true_regnum (SUBREG_REG (x));
if (base >= 0 && base < FIRST_PSEUDO_REGISTER)
return SUBREG_WORD (x) + base;
}
return -1;
}
static int *same_regs;
static int num_same_regs;
static char *modified_regs;
static int modified_mem;
static void
mark_modified_reg (dest, x)
rtx dest;
rtx x ATTRIBUTE_UNUSED;
{
int regno, i;
if (GET_CODE (dest) == SUBREG)
dest = SUBREG_REG (dest);
if (GET_CODE (dest) == MEM)
modified_mem = 1;
if (GET_CODE (dest) != REG)
return;
regno = REGNO (dest);
if (regno >= FIRST_PSEUDO_REGISTER)
modified_regs[regno] = 1;
else
for (i = 0; i < HARD_REGNO_NREGS (regno, GET_MODE (dest)); i++)
modified_regs[regno + i] = 1;
}
void
thread_jumps (f, max_reg, flag_before_loop)
rtx f;
int max_reg;
int flag_before_loop;
{
rtx label, b1, b2, t1, t2;
enum rtx_code code1, code2;
rtx b1op0, b1op1, b2op0, b2op1;
int changed = 1;
int i;
int *all_reset;
modified_regs = (char *) alloca (max_reg * sizeof (char));
same_regs = (int *) alloca (max_reg * sizeof (int));
all_reset = (int *) alloca (max_reg * sizeof (int));
for (i = 0; i < max_reg; i++)
all_reset[i] = -1;
while (changed)
{
changed = 0;
for (b1 = f; b1; b1 = NEXT_INSN (b1))
{
if (GET_CODE (b1) != JUMP_INSN
|| ! condjump_p (b1) || simplejump_p (b1)
|| JUMP_LABEL (b1) == 0)
continue;
bzero (modified_regs, max_reg * sizeof (char));
modified_mem = 0;
bcopy ((char *) all_reset, (char *) same_regs,
max_reg * sizeof (int));
num_same_regs = 0;
label = JUMP_LABEL (b1);
for (b2 = NEXT_INSN (label); b2; b2 = NEXT_INSN (b2))
{
if (GET_CODE (b2) == CODE_LABEL)
break;
else if (GET_CODE (b2) == JUMP_INSN)
{
if (simplejump_p (b2)
&& JUMP_LABEL (b2) != 0
&& LABEL_NUSES (JUMP_LABEL (b2)) == 1)
{
b2 = JUMP_LABEL (b2);
continue;
}
else
break;
}
if (GET_CODE (b2) != CALL_INSN && GET_CODE (b2) != INSN)
continue;
if (GET_CODE (b2) == CALL_INSN)
{
modified_mem = 1;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (call_used_regs[i] && ! fixed_regs[i]
&& i != STACK_POINTER_REGNUM
&& i != FRAME_POINTER_REGNUM
&& i != HARD_FRAME_POINTER_REGNUM
&& i != ARG_POINTER_REGNUM)
modified_regs[i] = 1;
}
note_stores (PATTERN (b2), mark_modified_reg);
}
if (b2 == 0
|| GET_CODE (b2) != JUMP_INSN
|| b2 == b1
|| ! condjump_p (b2)
|| simplejump_p (b2))
continue;
b1op0 = XEXP (XEXP (SET_SRC (PATTERN (b1)), 0), 0);
b1op1 = XEXP (XEXP (SET_SRC (PATTERN (b1)), 0), 1);
code1 = GET_CODE (XEXP (SET_SRC (PATTERN (b1)), 0));
if (XEXP (SET_SRC (PATTERN (b1)), 1) == pc_rtx)
code1 = reverse_condition (code1);
b2op0 = XEXP (XEXP (SET_SRC (PATTERN (b2)), 0), 0);
b2op1 = XEXP (XEXP (SET_SRC (PATTERN (b2)), 0), 1);
code2 = GET_CODE (XEXP (SET_SRC (PATTERN (b2)), 0));
if (XEXP (SET_SRC (PATTERN (b2)), 1) == pc_rtx)
code2 = reverse_condition (code2);
if (rtx_equal_for_thread_p (b1op0, b2op0, b2)
&& rtx_equal_for_thread_p (b1op1, b2op1, b2)
&& (comparison_dominates_p (code1, code2)
|| (comparison_dominates_p (code1, reverse_condition (code2))
&& can_reverse_comparison_p (XEXP (SET_SRC (PATTERN (b1)),
0),
b1))))
{
t1 = prev_nonnote_insn (b1);
t2 = prev_nonnote_insn (b2);
while (t1 != 0 && t2 != 0)
{
if (t2 == label)
{
rtx new_label;
if (num_same_regs != 0)
break;
if (comparison_dominates_p (code1, code2))
new_label = JUMP_LABEL (b2);
else
new_label = get_label_after (b2);
if (JUMP_LABEL (b1) != new_label)
{
rtx prev = PREV_INSN (new_label);
if (flag_before_loop
&& GET_CODE (prev) == NOTE
&& NOTE_LINE_NUMBER (prev) == NOTE_INSN_LOOP_BEG)
{
new_label = gen_label_rtx ();
emit_label_after (new_label, PREV_INSN (prev));
}
changed |= redirect_jump (b1, new_label);
}
break;
}
if (GET_CODE (t1) != INSN || GET_CODE (t2) != INSN
|| recog_memoized (t1) != recog_memoized (t2)
|| ! rtx_equal_for_thread_p (PATTERN (t1),
PATTERN (t2), t2))
break;
t1 = prev_nonnote_insn (t1);
t2 = prev_nonnote_insn (t2);
}
}
}
}
}
int
rtx_equal_for_thread_p (x, y, yinsn)
rtx x, y;
rtx yinsn;
{
register int i;
register int j;
register enum rtx_code code;
register char *fmt;
code = GET_CODE (x);
if (code != GET_CODE (y))
return 0;
if (GET_MODE (x) != GET_MODE (y))
return 0;
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
&& FLOAT_MODE_P (GET_MODE (x)) && ! flag_fast_math)
return 0;
if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
return ((rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn)
&& rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 1), yinsn))
|| (rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 1), yinsn)
&& rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 0), yinsn)));
else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
return (rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn)
&& rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 1), yinsn));
else if (GET_RTX_CLASS (code) == '1')
return rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn);
switch (code)
{
case REG:
if (REGNO (x) == REGNO (y) && ! modified_regs[REGNO (x)])
return 1;
if (REG_USERVAR_P (x) || REG_USERVAR_P (y)
|| REGNO (x) < FIRST_PSEUDO_REGISTER
|| REGNO (y) < FIRST_PSEUDO_REGISTER)
return 0;
if (same_regs[REGNO (x)] == -1)
{
same_regs[REGNO (x)] = REGNO (y);
num_same_regs++;
if (REGNO_LAST_UID (REGNO (y)) != INSN_UID (yinsn))
return 0;
return 1;
}
else
return (same_regs[REGNO (x)] == REGNO (y));
break;
case MEM:
if (modified_mem || MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
return 0;
return rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn);
case ASM_INPUT:
if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
return 0;
break;
case SET:
if (GET_CODE (SET_DEST (x)) == REG
&& GET_CODE (SET_DEST (y)) == REG)
{
if (same_regs[REGNO (SET_DEST (x))] == REGNO (SET_DEST (y)))
{
same_regs[REGNO (SET_DEST (x))] = -1;
num_same_regs--;
}
else if (REGNO (SET_DEST (x)) != REGNO (SET_DEST (y)))
return 0;
}
else
if (rtx_equal_for_thread_p (SET_DEST (x), SET_DEST (y), yinsn) == 0)
return 0;
return rtx_equal_for_thread_p (SET_SRC (x), SET_SRC (y), yinsn);
case LABEL_REF:
return XEXP (x, 0) == XEXP (y, 0);
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
default:
break;
}
if (x == y)
return 1;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
switch (fmt[i])
{
case 'w':
if (XWINT (x, i) != XWINT (y, i))
return 0;
break;
case 'n':
case 'i':
if (XINT (x, i) != XINT (y, i))
return 0;
break;
case 'V':
case 'E':
if (XVECLEN (x, i) != XVECLEN (y, i))
return 0;
for (j = 0; j < XVECLEN (x, i); j++)
if (rtx_equal_for_thread_p (XVECEXP (x, i, j),
XVECEXP (y, i, j), yinsn) == 0)
return 0;
break;
case 'e':
if (rtx_equal_for_thread_p (XEXP (x, i), XEXP (y, i), yinsn) == 0)
return 0;
break;
case 'S':
case 's':
if (strcmp (XSTR (x, i), XSTR (y, i)))
return 0;
break;
case 'u':
break;
case '0':
break;
default:
abort ();
}
}
return 1;
}
#ifndef HAVE_cc0
static rtx
find_insert_position (insn, new)
rtx insn;
rtx new;
{
int i;
rtx prev;
if (GET_CODE (PATTERN (new)) != PARALLEL)
return insn;
for (i = XVECLEN (PATTERN (new), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (new), 0, i)) == CLOBBER
&& reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (new), 0, i), 0),
insn))
break;
if (i < 0)
return insn;
prev = prev_active_insn (insn);
for (i = XVECLEN (PATTERN (new), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (new), 0, i)) == CLOBBER
&& reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (new), 0, i), 0),
insn)
&& ! modified_in_p (XEXP (XVECEXP (PATTERN (new), 0, i), 0),
prev))
return 0;
return reg_mentioned_p (SET_DEST (single_set (new)), prev) ? 0 : prev;
}
#endif