rs6000-protos.h: Add output_cbranch.
* 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. From-SVN: r33686
This commit is contained in:
parent
233844c0ea
commit
12a4e8c50d
|
@ -1,3 +1,12 @@
|
|||
2000-05-04 Geoff Keating <geoffk@cygnus.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2000-05-04 Jason Merrill <jason@casey.cygnus.com>
|
||||
|
||||
* simplify-rtx.c (simplify_ternary_operation): Cast to unsigned.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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")])
|
||||
|
||||
|
|
Loading…
Reference in New Issue