summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorgeoffk <geoffk@138bc75d-0d04-0410-961f-82ee72b054a4>2000-05-04 22:15:23 +0000
committergeoffk <geoffk@138bc75d-0d04-0410-961f-82ee72b054a4>2000-05-04 22:15:23 +0000
commit2b3dfdb8611ae5a53b9a321c47c94a9182b12326 (patch)
treed493f07d81ae30e20225cca33c92741716320b92 /gcc/config
parent0618cd1d59bfb4ceb0aa6382de739c47343c9fb3 (diff)
downloadgcc-2b3dfdb8611ae5a53b9a321c47c94a9182b12326.tar.gz
* config/rs6000/rs6000-protos.h: Add output_cbranch.
* config/rs6000/rs6000.c (ccr_bit_negated_p): Delete. (print_operand): Delete %t and %T codes. (output_cbranch): New function. Support branch prediction. * config/rs6000/rs6000.md: Use output_cbranch for conditional branches and returns. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33686 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/rs6000/rs6000-protos.h1
-rw-r--r--gcc/config/rs6000/rs6000.c171
-rw-r--r--gcc/config/rs6000/rs6000.md21
3 files changed, 135 insertions, 58 deletions
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index c63360705a7..05201afafca 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -84,6 +84,7 @@ extern enum reg_class secondary_reload_class PARAMS ((enum reg_class,
extern int ccr_bit PARAMS ((rtx, int));
extern void print_operand PARAMS ((FILE *, rtx, int));
extern void print_operand_address PARAMS ((FILE *, rtx));
+extern char * output_cbranch PARAMS ((rtx, const char *, int, rtx));
extern void output_toc PARAMS ((FILE *, rtx, int));
extern int rs6000_adjust_cost PARAMS ((rtx, rtx, rtx, int));
extern int rs6000_adjust_priority PARAMS ((rtx, int));
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 215b8121c27..36c50b429cc 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -119,7 +119,6 @@ static int rs6000_sr_alias_set;
static void rs6000_add_gc_roots PARAMS ((void));
static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT));
static rtx expand_block_move_mem PARAMS ((enum machine_mode, rtx, rtx));
-static int ccr_bit_negated_p PARAMS((rtx));
static void rs6000_emit_stack_tie PARAMS ((void));
static void rs6000_frame_related PARAMS ((rtx, rtx, HOST_WIDE_INT, rtx, rtx));
static void rs6000_emit_allocate_stack PARAMS ((HOST_WIDE_INT, int));
@@ -3195,29 +3194,6 @@ ccr_bit (op, scc_p)
abort ();
}
}
-
-/* Given a comparison operation, say whether the bit tested (as returned
- by ccr_bit) should be negated. */
-
-static int
-ccr_bit_negated_p (op)
- rtx op;
-{
- enum rtx_code code = GET_CODE (op);
- enum machine_mode mode = GET_MODE (XEXP (op, 0));
-
- if (code == EQ
- || code == LT || code == GT
- || code == LTU || code == GTU)
- return 0;
- else if (mode != CCFPmode
- || code == NE
- || code == ORDERED
- || code == UNGE || code == UNLE)
- return 1;
- else
- return 0;
-}
/* Return the GOT register. */
@@ -3732,29 +3708,6 @@ print_operand (file, x, code)
return;
}
- case 't':
- /* Write 12 if this jump operation will branch if true, 4 otherwise. */
- if (GET_RTX_CLASS (GET_CODE (x)) != '<')
- output_operand_lossage ("invalid %%t value");
-
- else if (! ccr_bit_negated_p (x))
- fputs ("12", file);
- else
- putc ('4', file);
- return;
-
- case 'T':
- /* Opposite of 't': write 4 if this jump operation will branch if true,
- 12 otherwise. */
- if (GET_RTX_CLASS (GET_CODE (x)) != '<')
- output_operand_lossage ("invalid %%T value");
-
- else if (! ccr_bit_negated_p (x))
- putc ('4', file);
- else
- fputs ("12", file);
- return;
-
case 'u':
/* High-order 16 bits of constant for use in unsigned operand. */
if (! INT_P (x))
@@ -4011,6 +3964,130 @@ print_operand_address (file, x)
abort ();
}
+/* Return the string to output a conditional branch to LABEL, which is
+ the operand number of the label, or -1 if the branch is really a
+ conditional return.
+
+ OP is the conditional expression. XEXP (OP, 0) is assumed to be a
+ condition code register and its mode specifies what kind of
+ comparison we made.
+
+ REVERSED is non-zero if we should reverse the sense of the comparison.
+
+ INSN is the insn. */
+
+char *
+output_cbranch (op, label, reversed, insn)
+ rtx op;
+ const char * label;
+ int reversed;
+ rtx insn;
+{
+ static char string[64];
+ enum rtx_code code = GET_CODE (op);
+ rtx cc_reg = XEXP (op, 0);
+ enum machine_mode mode = GET_MODE (cc_reg);
+ int cc_regno = REGNO (cc_reg) - CR0_REGNO;
+ int need_longbranch = label != NULL && get_attr_length (insn) == 12;
+ int really_reversed = reversed ^ need_longbranch;
+ char *s = string;
+ const char *ccode;
+ const char *pred;
+ rtx note;
+
+ /* Work out which way this really branches. */
+ if (really_reversed)
+ {
+ /* Reversal of FP compares takes care -- an ordered compare
+ becomes an unordered compare and vice versa. */
+ if (mode == CCFPmode)
+ code = reverse_condition_maybe_unordered (code);
+ else
+ code = reverse_condition (code);
+ }
+
+ /* If needed, print the CROR required for various floating-point
+ comparisons; and decide on the condition code to test. */
+ if ((code == LE || code == GE
+ || code == UNEQ || code == LTGT
+ || code == UNGT || code == UNLT)
+ && mode == CCFPmode)
+ {
+ int base_bit = 4 * cc_regno;
+ int bit0, bit1;
+
+ if (code == UNEQ)
+ bit0 = 2;
+ else if (code == UNGT || code == GE)
+ bit0 = 1;
+ else
+ bit0 = 0;
+ if (code == LTGT)
+ bit1 = 1;
+ else if (code == LE || code == GE)
+ bit1 = 2;
+ else
+ bit1 = 3;
+
+ s += sprintf (s, "cror %d,%d,%d\n\t", base_bit + 3,
+ base_bit + bit1, base_bit + bit0);
+ ccode = "so";
+ }
+ else switch (code)
+ {
+ /* Not all of these are actually distinct opcodes, but
+ we distinguish them for clarity of the resulting assembler. */
+ case NE: ccode = "ne"; break;
+ case EQ: ccode = "eq"; break;
+ case GE: case GEU: ccode = "ge"; break;
+ case GT: case GTU: ccode = "gt"; break;
+ case LE: case LEU: ccode = "le"; break;
+ case LT: case LTU: ccode = "lt"; break;
+ case UNORDERED: ccode = "un"; break;
+ case ORDERED: ccode = "nu"; break;
+ case UNGE: ccode = "nl"; break;
+ case UNLE: ccode = "ng"; break;
+ default:
+ abort();
+ }
+
+ /* Maybe we have a guess as to how likely the branch is. */
+ note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
+ if (note != NULL_RTX)
+ {
+ /* PROB is the difference from 50%. */
+ int prob = INTVAL (XEXP (note, 0)) - REG_BR_PROB_BASE / 2;
+
+ /* For branches that are very close to 50%, assume not-taken. */
+ if (abs (prob) > REG_BR_PROB_BASE / 20
+ && ((prob > 0) ^ need_longbranch))
+ pred = "+";
+ else
+ pred = "-";
+ }
+ else
+ pred = "";
+
+ if (label == NULL)
+ s += sprintf (s, "{b%sr|b%slr}%s ", ccode, ccode, pred);
+ else
+ s += sprintf (s, "b%s%s ", ccode, pred);
+
+ s += sprintf (s, "cr%d", cc_regno);
+
+ if (label != NULL)
+ {
+ /* If the branch distance was too far, we may have to use an
+ unconditional branch to go the distance. */
+ if (need_longbranch)
+ s += sprintf (s, ",%c$+8 ; b %s", '%', label);
+ else
+ s += sprintf (s, ",%s", label);
+ }
+
+ return string;
+}
+
/* This page contains routines that are used to determine what the function
prologue and epilogue code will do and write them out. */
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 4573330a820..66a23508cf7 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -13992,11 +13992,7 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
""
"*
{
- if (get_attr_length (insn) == 8)
- return \"%C1bc %t1,%j1,%l0\";
- else
- return \"%C1bc %T1,%j1,%$+8\;b %l0\";
-
+ return output_cbranch (operands[1], \"%l0\", 0, insn);
}"
[(set_attr "type" "branch")])
@@ -14009,7 +14005,10 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
(return)
(pc)))]
"direct_return ()"
- "{%C0bcr|%C0bclr} %t0,%j0"
+ "*
+{
+ return output_cbranch (operands[0], NULL, 0, insn);
+}"
[(set_attr "type" "branch")
(set_attr "length" "8")])
@@ -14024,10 +14023,7 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
""
"*
{
- if (get_attr_length (insn) == 8)
- return \"%C1bc %T1,%j1,%l0\";
- else
- return \"%C1bc %t1,%j1,%$+8\;b %l0\";
+ return output_cbranch (operands[1], \"%l0\", 1, insn);
}"
[(set_attr "type" "branch")])
@@ -14040,7 +14036,10 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
(pc)
(return)))]
"direct_return ()"
- "{%C0bcr|%C0bclr} %T0,%j0"
+ "*
+{
+ return output_cbranch (operands[0], NULL, 1, insn);
+}"
[(set_attr "type" "branch")
(set_attr "length" "8")])