aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/pa/pa.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/pa/pa.c')
-rw-r--r--gcc/config/pa/pa.c103
1 files changed, 82 insertions, 21 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 8adf58625f0..c2d7058e48c 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -3230,27 +3230,6 @@ print_operand (file, x, code)
abort ();
}
return;
- /* Reversed floating point comparison. Need special conditions to
- deal with NaNs properly. */
- case 'y':
- switch (GET_CODE (x))
- {
- case EQ:
- fputs ("=", file); break;
- case NE:
- fputs ("!=", file); break;
- case GT:
- fputs ("!<=", file); break;
- case GE:
- fputs ("!<", file); break;
- case LT:
- fputs ("!>=", file); break;
- case LE:
- fputs ("!>", file); break;
- default:
- abort ();
- }
- return;
case 'S': /* Condition, operands are (S)wapped. */
switch (GET_CODE (x))
{
@@ -5525,6 +5504,88 @@ pa_reorg (insns)
/* This is fairly cheap, so always run it if optimizing. */
if (optimize > 0)
{
+ /* Find all floating point compare + branch insns. If possible,
+ reverse the comparison & the branch to avoid add,tr insns. */
+ insns = get_insns ();
+ for (insn = insns; insn; insn = NEXT_INSN (insn))
+ {
+ rtx tmp, next_insn;
+
+ /* Ignore anything that isn't an INSN. */
+ if (GET_CODE (insn) != INSN)
+ continue;
+
+ tmp = PATTERN (insn);
+
+ /* It must be a set. */
+ if (GET_CODE (tmp) != SET)
+ continue;
+
+ /* The destination must be CCFP, which is register zero. */
+ tmp = SET_DEST (tmp);
+ if (GET_CODE (tmp) != REG || REGNO (tmp) != 0)
+ continue;
+
+ /* INSN should be a set of CCFP.
+
+ See if the result of this insn is used in a reversed FP
+ conditional branch. If so, reverse our condition and
+ the branch. Doing so avoids useless add,tr insns. */
+ next_insn = NEXT_INSN (insn);
+ while (next_insn)
+ {
+ /* Jumps, calls and labels stop our search. */
+ if (GET_CODE (next_insn) == JUMP_INSN
+ || GET_CODE (next_insn) == CALL_INSN
+ || GET_CODE (next_insn) == CODE_LABEL)
+ break;
+
+ /* As does another fcmp insn. */
+ if (GET_CODE (next_insn) == INSN
+ && GET_CODE (PATTERN (next_insn)) == SET
+ && GET_CODE (SET_DEST (PATTERN (next_insn))) == REG
+ && REGNO (SET_DEST (PATTERN (next_insn))) == 0)
+ break;
+
+ next_insn = NEXT_INSN (next_insn);
+ }
+
+ /* Is NEXT_INSN a branch? */
+ if (next_insn
+ && GET_CODE (next_insn) == JUMP_INSN)
+ {
+ rtx pattern = PATTERN (next_insn);
+
+ /* If it a reversed fp conditional branch (eg uses add,tr)
+ and CCFP dies, then reverse our conditional and the branch
+ to avoid the add,tr. */
+ if (GET_CODE (pattern) == SET
+ && SET_DEST (pattern) == pc_rtx
+ && GET_CODE (SET_SRC (pattern)) == IF_THEN_ELSE
+ && GET_CODE (XEXP (SET_SRC (pattern), 0)) == NE
+ && GET_CODE (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == REG
+ && REGNO (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == 0
+ && GET_CODE (XEXP (SET_SRC (pattern), 1)) == PC
+ && find_regno_note (next_insn, REG_DEAD, 0))
+ {
+ /* Reverse the branch. */
+ tmp = XEXP (SET_SRC (pattern), 1);
+ XEXP (SET_SRC (pattern), 1) = XEXP (SET_SRC (pattern), 2);
+ XEXP (SET_SRC (pattern), 2) = tmp;
+ INSN_CODE (next_insn) = -1;
+
+ /* Reverse our condition. */
+ tmp = PATTERN (insn);
+ PUT_CODE (XEXP (tmp, 1),
+ reverse_condition (GET_CODE (XEXP (tmp, 1))));
+ }
+ }
+ }
+ }
+
+ /* This is fairly cheap, so always run it if optimizing. */
+ if (optimize > 0)
+ {
/* Find and explode all ADDR_VEC insns. */
insns = get_insns ();
for (insn = insns; insn; insn = NEXT_INSN (insn))