Commit 39a10a29 by Geoff Keating Committed by Geoffrey Keating

rs6000.c (validate_condition_mode): New function.

* config/rs6000/rs6000.c (validate_condition_mode): New function.
(branch_comparison_operator): Call validate_condition_mode to
abort rather than returning 0.
(branch_positive_comparison_operator): New function.
(scc_comparison_operator): Call validate_condition_mode to abort
rather than returning 0.
(ccr_bit): Call validate_condition_mode.  Update for
new branch scheme.
(print_operand): Delete %C modifier.  Update %E case
to use EQ bit not SO bit.
(rs6000_reverse_condition): New function.
(rs6000_generate_compare): New function.
(rs6000_emit_sCOND): New function.
(rs6000_emit_cbranch): New function.
(output_cbranch): The length of a long branch insn is
now only 8 bytes.  Add validate_condition_mode.  Use
rs6000_reverse_condition.  Remove cror generation.
* config/rs6000/rs6000.h: Update comments.
(PREDICATE_CODES): Add new predicate.  Update codes used
by branch_comparison_operator and scc_comparison_operator.
* config/rs6000/rs6000-protos.h: Add prototypes for
new external functions.
* config/rs6000/rs6000.md: Add new scheduling parameters
for cr_logical instructions.  Change length of branch
instructions.
(bCOND patterns): Call rs6000_emit_cbranch.
(sCOND patterns): Call rs6000_emit_sCOND.
(branch patterns): Change lengths to 4.
(cr logical patterns): New.

From-SVN: r36191
parent 6e92b232
2000-09-06 Geoff Keating <geoffk@cygnus.com>
* config/rs6000/rs6000.c (validate_condition_mode): New function.
(branch_comparison_operator): Call validate_condition_mode to
abort rather than returning 0.
(branch_positive_comparison_operator): New function.
(scc_comparison_operator): Call validate_condition_mode to abort
rather than returning 0.
(ccr_bit): Call validate_condition_mode. Update for
new branch scheme.
(print_operand): Delete %C modifier. Update %E case
to use EQ bit not SO bit.
(rs6000_reverse_condition): New function.
(rs6000_generate_compare): New function.
(rs6000_emit_sCOND): New function.
(rs6000_emit_cbranch): New function.
(output_cbranch): The length of a long branch insn is
now only 8 bytes. Add validate_condition_mode. Use
rs6000_reverse_condition. Remove cror generation.
* config/rs6000/rs6000.h: Update comments.
(PREDICATE_CODES): Add new predicate. Update codes used
by branch_comparison_operator and scc_comparison_operator.
* config/rs6000/rs6000-protos.h: Add prototypes for
new external functions.
* config/rs6000/rs6000.md: Add new scheduling parameters
for cr_logical instructions. Change length of branch
instructions.
(bCOND patterns): Call rs6000_emit_cbranch.
(sCOND patterns): Call rs6000_emit_sCOND.
(branch patterns): Change lengths to 4.
(cr logical patterns): New.
2000-09-06 Richard Henderson <rth@cygnus.com> 2000-09-06 Richard Henderson <rth@cygnus.com>
* config/i386/i386.md (call_pop): Fix test for setting * config/i386/i386.md (call_pop): Fix test for setting
......
...@@ -73,6 +73,8 @@ extern int expand_block_move PARAMS ((rtx[])); ...@@ -73,6 +73,8 @@ extern int expand_block_move PARAMS ((rtx[]));
extern int load_multiple_operation PARAMS ((rtx, enum machine_mode)); extern int load_multiple_operation PARAMS ((rtx, enum machine_mode));
extern int store_multiple_operation PARAMS ((rtx, enum machine_mode)); extern int store_multiple_operation PARAMS ((rtx, enum machine_mode));
extern int branch_comparison_operator PARAMS ((rtx, enum machine_mode)); extern int branch_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int branch_positive_comparison_operator
PARAMS ((rtx, enum machine_mode));
extern int scc_comparison_operator PARAMS ((rtx, enum machine_mode)); extern int scc_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int trap_comparison_operator PARAMS ((rtx, enum machine_mode)); extern int trap_comparison_operator PARAMS ((rtx, enum machine_mode));
extern int boolean_operator PARAMS ((rtx, enum machine_mode)); extern int boolean_operator PARAMS ((rtx, enum machine_mode));
...@@ -87,6 +89,10 @@ extern enum reg_class secondary_reload_class PARAMS ((enum reg_class, ...@@ -87,6 +89,10 @@ extern enum reg_class secondary_reload_class PARAMS ((enum reg_class,
extern int ccr_bit PARAMS ((rtx, int)); extern int ccr_bit PARAMS ((rtx, int));
extern void print_operand PARAMS ((FILE *, rtx, int)); extern void print_operand PARAMS ((FILE *, rtx, int));
extern void print_operand_address PARAMS ((FILE *, rtx)); extern void print_operand_address PARAMS ((FILE *, rtx));
extern enum rtx_code rs6000_reverse_condition PARAMS ((enum machine_mode,
enum rtx_code));
extern void rs6000_emit_sCOND PARAMS ((enum rtx_code, rtx));
extern void rs6000_emit_cbranch PARAMS ((enum rtx_code, rtx));
extern char * output_cbranch PARAMS ((rtx, const char *, int, rtx)); extern char * output_cbranch PARAMS ((rtx, const char *, int, rtx));
extern void output_toc PARAMS ((FILE *, rtx, int, enum machine_mode)); extern void output_toc PARAMS ((FILE *, rtx, int, enum machine_mode));
extern int rs6000_adjust_cost PARAMS ((rtx, rtx, rtx, int)); extern int rs6000_adjust_cost PARAMS ((rtx, rtx, rtx, int));
......
...@@ -119,6 +119,9 @@ static int rs6000_sr_alias_set; ...@@ -119,6 +119,9 @@ static int rs6000_sr_alias_set;
static void rs6000_add_gc_roots PARAMS ((void)); static void rs6000_add_gc_roots PARAMS ((void));
static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT)); static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT));
static rtx expand_block_move_mem PARAMS ((enum machine_mode, rtx, rtx)); static rtx expand_block_move_mem PARAMS ((enum machine_mode, rtx, rtx));
static void validate_condition_mode
PARAMS ((enum rtx_code, enum machine_mode));
static rtx rs6000_generate_compare PARAMS ((enum rtx_code));
static void rs6000_maybe_dead PARAMS ((rtx)); static void rs6000_maybe_dead PARAMS ((rtx));
static void rs6000_emit_stack_tie PARAMS ((void)); static void rs6000_emit_stack_tie PARAMS ((void));
static void rs6000_frame_related PARAMS ((rtx, rtx, HOST_WIDE_INT, rtx, rtx)); static void rs6000_frame_related PARAMS ((rtx, rtx, HOST_WIDE_INT, rtx, rtx));
...@@ -3212,6 +3215,48 @@ stmw_operation (op, mode) ...@@ -3212,6 +3215,48 @@ stmw_operation (op, mode)
return 1; return 1;
} }
/* A validation routine: say whether CODE, a condition code,
and MODE match. The other alternatives either don't make
sense or should never be generated. */
static void
validate_condition_mode (code, mode)
enum rtx_code code;
enum machine_mode mode;
{
if (GET_RTX_CLASS (code) != '<'
|| GET_MODE_CLASS (mode) != MODE_CC)
abort ();
/* These don't make sense. */
if ((code == GT || code == LT || code == GE || code == LE)
&& mode == CCUNSmode)
abort ();
if ((code == GTU || code == LTU || code == GEU || code == LEU)
&& mode != CCUNSmode)
abort ();
if (mode != CCFPmode
&& (code == ORDERED || code == UNORDERED
|| code == UNEQ || code == LTGT
|| code == UNGT || code == UNLT
|| code == UNGE || code == UNLE))
abort();
/* These should never be generated. */
if (mode == CCFPmode
&& (code == LE || code == GE
|| code == UNEQ || code == LTGT
|| code == UNGT || code == UNLT))
abort ();
/* These are invalid; the information is not there. */
if (mode == CCEQmode
&& code != EQ && code != NE)
abort ();
}
/* Return 1 if OP is a comparison operation that is valid for a branch insn. /* Return 1 if OP is a comparison operation that is valid for a branch insn.
We only check the opcode against the mode of the CC value here. */ We only check the opcode against the mode of the CC value here. */
...@@ -3230,17 +3275,32 @@ branch_comparison_operator (op, mode) ...@@ -3230,17 +3275,32 @@ branch_comparison_operator (op, mode)
if (GET_MODE_CLASS (cc_mode) != MODE_CC) if (GET_MODE_CLASS (cc_mode) != MODE_CC)
return 0; return 0;
if ((code == GT || code == LT || code == GE || code == LE) validate_condition_mode (code, cc_mode);
&& cc_mode == CCUNSmode)
return 0;
if ((code == GTU || code == LTU || code == GEU || code == LEU) return 1;
&& (cc_mode != CCUNSmode)) }
/* Return 1 if OP is a comparison operation that is valid for a branch
insn and which is true if the corresponding bit in the CC register
is set. */
int
branch_positive_comparison_operator (op, mode)
register rtx op;
enum machine_mode mode;
{
enum rtx_code code;
if (! branch_comparison_operator (op, mode))
return 0; return 0;
return 1; code = GET_CODE (op);
return (code == EQ || code == LT || code == GT
|| code == LTU || code == GTU
|| code == UNORDERED);
} }
/* Return 1 if OP is a comparison operation that is valid for an scc insn. /* Return 1 if OP is a comparison operation that is valid for an scc insn.
We check the opcode against the mode of the CC value and disallow EQ or We check the opcode against the mode of the CC value and disallow EQ or
NE comparisons for integers. */ NE comparisons for integers. */
...@@ -3263,18 +3323,9 @@ scc_comparison_operator (op, mode) ...@@ -3263,18 +3323,9 @@ scc_comparison_operator (op, mode)
if (GET_MODE_CLASS (cc_mode) != MODE_CC) if (GET_MODE_CLASS (cc_mode) != MODE_CC)
return 0; return 0;
if (code == NE && cc_mode != CCFPmode) validate_condition_mode (code, cc_mode);
return 0;
if ((code == GT || code == LT || code == GE || code == LE)
&& cc_mode == CCUNSmode)
return 0;
if ((code == GTU || code == LTU || code == GEU || code == LEU)
&& (cc_mode != CCUNSmode))
return 0;
if (cc_mode == CCEQmode && code != EQ && code != NE) if (code == NE && cc_mode != CCFPmode)
return 0; return 0;
return 1; return 1;
...@@ -3287,8 +3338,7 @@ trap_comparison_operator (op, mode) ...@@ -3287,8 +3338,7 @@ trap_comparison_operator (op, mode)
{ {
if (mode != VOIDmode && mode != GET_MODE (op)) if (mode != VOIDmode && mode != GET_MODE (op))
return 0; return 0;
return (GET_RTX_CLASS (GET_CODE (op)) == '<' return GET_RTX_CLASS (GET_CODE (op)) == '<';
|| GET_CODE (op) == EQ || GET_CODE (op) == NE);
} }
int int
...@@ -3538,11 +3588,7 @@ ccr_bit (op, scc_p) ...@@ -3538,11 +3588,7 @@ ccr_bit (op, scc_p)
cc_regnum = REGNO (reg); cc_regnum = REGNO (reg);
base_bit = 4 * (cc_regnum - CR0_REGNO); base_bit = 4 * (cc_regnum - CR0_REGNO);
/* In CCEQmode cases we have made sure that the result is always in the validate_condition_mode (code, cc_mode);
third bit of the CR field. */
if (cc_mode == CCEQmode)
return base_bit + 3;
switch (code) switch (code)
{ {
...@@ -3558,16 +3604,13 @@ ccr_bit (op, scc_p) ...@@ -3558,16 +3604,13 @@ ccr_bit (op, scc_p)
return base_bit + 3; return base_bit + 3;
case GE: case GEU: case GE: case GEU:
/* If floating-point, we will have done a cror to put the bit in the /* If scc, we will have done a cror to put the bit in the
unordered position. So test that bit. For integer, this is ! LT unordered position. So test that bit. For integer, this is ! LT
unless this is an scc insn. */ unless this is an scc insn. */
return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit; return scc_p ? base_bit + 3 : base_bit;
case LE: case LEU: case LE: case LEU:
return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit + 1; return scc_p ? base_bit + 3 : base_bit + 1;
case UNEQ: case UNGT: case UNLT: case LTGT:
return base_bit + 3;
default: default:
abort (); abort ();
...@@ -3710,40 +3753,11 @@ print_operand (file, x, code) ...@@ -3710,40 +3753,11 @@ print_operand (file, x, code)
/* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
output_operand. */ output_operand. */
case 'C':
{
enum rtx_code code = GET_CODE (x);
/* This is an optional cror needed for certain floating-point
comparisons. Otherwise write nothing. */
if ((code == LE || code == GE
|| code == UNEQ || code == LTGT
|| code == UNGT || code == UNLT)
&& GET_MODE (XEXP (x, 0)) == CCFPmode)
{
int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_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;
fprintf (file, "cror %d,%d,%d\n\t", base_bit + 3,
base_bit + bit1, base_bit + bit0);
}
}
return;
case 'D': case 'D':
/* There used to be a comment for 'C' reading "This is an
optional cror needed for certain floating-point
comparisons. Otherwise write nothing." */
/* Similar, except that this is for an scc, so we must be able to /* Similar, except that this is for an scc, so we must be able to
encode the test in a single bit that is one. We do the above encode the test in a single bit that is one. We do the above
for any LE, GE, GEU, or LEU and invert the bit for NE. */ for any LE, GE, GEU, or LEU and invert the bit for NE. */
...@@ -3767,11 +3781,11 @@ print_operand (file, x, code) ...@@ -3767,11 +3781,11 @@ print_operand (file, x, code)
return; return;
case 'E': case 'E':
/* X is a CR register. Print the number of the third bit of the CR */ /* X is a CR register. Print the number of the EQ bit of the CR */
if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x))) if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
output_operand_lossage ("invalid %%E value"); output_operand_lossage ("invalid %%E value");
else else
fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 3); fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 2);
return; return;
case 'f': case 'f':
...@@ -4013,7 +4027,9 @@ print_operand (file, x, code) ...@@ -4013,7 +4027,9 @@ print_operand (file, x, code)
case 'q': case 'q':
/* This outputs the logical code corresponding to a boolean /* This outputs the logical code corresponding to a boolean
expression. The expression may have one or both operands expression. The expression may have one or both operands
negated (if one, only the first one). */ negated (if one, only the first one). For condition register
logical operations, it will also treat the negated
CR codes as NOTs, but not handle NOTs of them. */
{ {
const char *const *t = 0; const char *const *t = 0;
const char *s; const char *s;
...@@ -4420,6 +4436,129 @@ print_operand_address (file, x) ...@@ -4420,6 +4436,129 @@ print_operand_address (file, x)
abort (); abort ();
} }
enum rtx_code
rs6000_reverse_condition (mode, code)
enum machine_mode mode;
enum rtx_code code;
{
/* 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);
}
/* Generate a compare for CODE. Return a brand-new rtx that
represents the result of the compare. */
static rtx
rs6000_generate_compare (code)
enum rtx_code code;
{
enum machine_mode comp_mode;
rtx compare_result;
if (rs6000_compare_fp_p)
comp_mode = CCFPmode;
else if (code == GTU || code == LTU
|| code == GEU || code == LEU)
comp_mode = CCUNSmode;
else
comp_mode = CCmode;
/* First, the compare. */
compare_result = gen_reg_rtx (comp_mode);
emit_insn (gen_rtx_SET (VOIDmode, compare_result,
gen_rtx_COMPARE (comp_mode,
rs6000_compare_op0,
rs6000_compare_op1)));
/* Some kinds of FP comparisons need an OR operation. */
if (rs6000_compare_fp_p
&& (code == LE || code == GE
|| code == UNEQ || code == LTGT
|| code == UNGT || code == UNLT))
{
enum rtx_code or1, or2;
rtx or1_rtx, or2_rtx, compare2_rtx;
rtx or_result = gen_reg_rtx (CCEQmode);
switch (code)
{
case LE: or1 = LT; or2 = EQ; break;
case GE: or1 = GT; or2 = EQ; break;
case UNEQ: or1 = UNORDERED; or2 = EQ; break;
case LTGT: or1 = LT; or2 = GT; break;
case UNGT: or1 = UNORDERED; or2 = GT; break;
case UNLT: or1 = UNORDERED; or2 = LT; break;
default: abort ();
}
validate_condition_mode (or1, comp_mode);
validate_condition_mode (or2, comp_mode);
or1_rtx = gen_rtx (or1, SImode, compare_result, const0_rtx);
or2_rtx = gen_rtx (or2, SImode, compare_result, const0_rtx);
compare2_rtx = gen_rtx_COMPARE (CCEQmode,
gen_rtx_IOR (SImode, or1_rtx, or2_rtx),
const_true_rtx);
emit_insn (gen_rtx_SET (VOIDmode, or_result, compare2_rtx));
compare_result = or_result;
code = EQ;
}
validate_condition_mode (code, GET_MODE (compare_result));
return gen_rtx (code, VOIDmode, compare_result, const0_rtx);
}
/* Emit the RTL for an sCOND pattern. */
void
rs6000_emit_sCOND (code, result)
enum rtx_code code;
rtx result;
{
rtx condition_rtx;
enum machine_mode op_mode;
condition_rtx = rs6000_generate_compare (code);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
{
PUT_MODE (condition_rtx, DImode);
convert_move (result, condition_rtx, 0);
}
else
{
PUT_MODE (condition_rtx, SImode);
emit_insn (gen_rtx_SET (VOIDmode, result, condition_rtx));
}
}
/* Emit a branch of kind CODE to location LOC. */
void
rs6000_emit_cbranch (code, loc)
enum rtx_code code;
rtx loc;
{
rtx condition_rtx, loc_ref;
condition_rtx = rs6000_generate_compare (code);
loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
loc_ref, pc_rtx)));
}
/* Return the string to output a conditional branch to LABEL, which is /* 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 the operand number of the label, or -1 if the branch is really a
conditional return. conditional return.
...@@ -4444,52 +4583,22 @@ output_cbranch (op, label, reversed, insn) ...@@ -4444,52 +4583,22 @@ output_cbranch (op, label, reversed, insn)
rtx cc_reg = XEXP (op, 0); rtx cc_reg = XEXP (op, 0);
enum machine_mode mode = GET_MODE (cc_reg); enum machine_mode mode = GET_MODE (cc_reg);
int cc_regno = REGNO (cc_reg) - CR0_REGNO; int cc_regno = REGNO (cc_reg) - CR0_REGNO;
int need_longbranch = label != NULL && get_attr_length (insn) == 12; int need_longbranch = label != NULL && get_attr_length (insn) == 8;
int really_reversed = reversed ^ need_longbranch; int really_reversed = reversed ^ need_longbranch;
char *s = string; char *s = string;
const char *ccode; const char *ccode;
const char *pred; const char *pred;
rtx note; rtx note;
/* Work out which way this really branches. */ validate_condition_mode (code, mode);
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 /* Work out which way this really branches. We could use
comparisons; and decide on the condition code to test. */ reverse_condition_maybe_unordered here always but this
if ((code == LE || code == GE makes the resulting assembler clearer. */
|| code == UNEQ || code == LTGT if (really_reversed)
|| code == UNGT || code == UNLT) code = rs6000_reverse_condition (mode, code);
&& 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, switch (code)
base_bit + bit1, base_bit + bit0);
ccode = "so";
}
else switch (code)
{ {
/* Not all of these are actually distinct opcodes, but /* Not all of these are actually distinct opcodes, but
we distinguish them for clarity of the resulting assembler. */ we distinguish them for clarity of the resulting assembler. */
......
...@@ -2275,18 +2275,19 @@ do { \ ...@@ -2275,18 +2275,19 @@ do { \
For the RS/6000, we need separate modes when unsigned (logical) comparisons For the RS/6000, we need separate modes when unsigned (logical) comparisons
are being done and we need a separate mode for floating-point. We also are being done and we need a separate mode for floating-point. We also
use a mode for the case when we are comparing the results of two use a mode for the case when we are comparing the results of two
comparisons. */ comparisons, as then only the EQ bit is valid in the register. */
#define EXTRA_CC_MODES \ #define EXTRA_CC_MODES \
CC(CCUNSmode, "CCUNS") \ CC(CCUNSmode, "CCUNS") \
CC(CCFPmode, "CCFP") \ CC(CCFPmode, "CCFP") \
CC(CCEQmode, "CCEQ") CC(CCEQmode, "CCEQ")
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, /* Given a comparison code (EQ, NE, etc.) and the first operand of a
return the mode to be used for the comparison. For floating-point, CCFPmode COMPARE, return the mode to be used for the comparison. For
should be used. CCUNSmode should be used for unsigned comparisons. floating-point, CCFPmode should be used. CCUNSmode should be used
CCEQmode should be used when we are doing an inequality comparison on for unsigned comparisons. CCEQmode should be used when we are
the result of a comparison. CCmode should be used in all other cases. */ doing an inequality comparison on the result of a
comparison. CCmode should be used in all other cases. */
#define SELECT_CC_MODE(OP,X,Y) \ #define SELECT_CC_MODE(OP,X,Y) \
(GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? CCFPmode \ (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? CCFPmode \
...@@ -2761,10 +2762,13 @@ do { \ ...@@ -2761,10 +2762,13 @@ do { \
{"branch_comparison_operator", {EQ, NE, LE, LT, GE, \ {"branch_comparison_operator", {EQ, NE, LE, LT, GE, \
GT, LEU, LTU, GEU, GTU, \ GT, LEU, LTU, GEU, GTU, \
UNORDERED, ORDERED, \ UNORDERED, ORDERED, \
UNEQ, LTGT, \ UNGE, UNLE }}, \
UNGE, UNGT, UNLE, UNLT}}, \ {"branch_positive_comparison_operator", {EQ, LT, GT, LTU, GTU, \
UNORDERED }}, \
{"scc_comparison_operator", {EQ, NE, LE, LT, GE, \ {"scc_comparison_operator", {EQ, NE, LE, LT, GE, \
GT, LEU, LTU, GEU, GTU}}, \ GT, LEU, LTU, GEU, GTU, \
UNORDERED, ORDERED, \
UNGE, UNLE }}, \
{"trap_comparison_operator", {EQ, NE, LE, LT, GE, \ {"trap_comparison_operator", {EQ, NE, LE, LT, GE, \
GT, LEU, LTU, GEU, GTU}}, \ GT, LEU, LTU, GEU, GTU}}, \
{"boolean_operator", {AND, IOR, XOR}}, \ {"boolean_operator", {AND, IOR, XOR}}, \
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
;; Define an insn type attribute. This is used in function unit delay ;; Define an insn type attribute. This is used in function unit delay
;; computations. ;; computations.
(define_attr "type" "integer,load,store,fpload,fpstore,imul,lmul,idiv,ldiv,branch,compare,delayed_compare,fpcompare,mtjmpr,fp,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg" (define_attr "type" "integer,load,store,fpload,fpstore,imul,lmul,idiv,ldiv,branch,compare,cr_logical,delayed_compare,fpcompare,mtjmpr,fp,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg"
(const_string "integer")) (const_string "integer"))
;; Length (in bytes). ;; Length (in bytes).
...@@ -47,8 +47,8 @@ ...@@ -47,8 +47,8 @@
(const_int -32768)) (const_int -32768))
(lt (minus (pc) (match_dup 0)) (lt (minus (pc) (match_dup 0))
(const_int 32767))) (const_int 32767)))
(const_int 8) (const_int 4)
(const_int 12)) (const_int 8))
(const_int 4))) (const_int 4)))
;; Processor type -- this attribute must exactly match the processor_type ;; Processor type -- this attribute must exactly match the processor_type
...@@ -124,6 +124,11 @@ ...@@ -124,6 +124,11 @@
1 1) 1 1)
(define_function_unit "iu" 1 0 (define_function_unit "iu" 1 0
(and (eq_attr "type" "cr_logical")
(eq_attr "cpu" "rios1,rs64a,mpccore,ppc403,ppc601"))
1 1)
(define_function_unit "iu" 1 0
(and (eq_attr "type" "imul") (and (eq_attr "type" "imul")
(eq_attr "cpu" "ppc403")) (eq_attr "cpu" "ppc403"))
4 4) 4 4)
...@@ -288,6 +293,15 @@ ...@@ -288,6 +293,15 @@
(eq_attr "cpu" "ppc750")) (eq_attr "cpu" "ppc750"))
19 19) 19 19)
; CR-logical operations are execute-serialized, that is they don't
; start (and block the function unit) until all preceding operations
; have finished. They don't block dispatch of other insns, though.
; I've imitated this by giving them longer latency.
(define_function_unit "sru" 1 0
(and (eq_attr "type" "cr_logical")
(eq_attr "cpu" "ppc603,ppc750"))
3 2)
; compare is done on integer unit, but feeds insns which ; compare is done on integer unit, but feeds insns which
; execute on the branch unit. ; execute on the branch unit.
(define_function_unit "iu" 1 0 (define_function_unit "iu" 1 0
...@@ -357,6 +371,17 @@ ...@@ -357,6 +371,17 @@
(eq_attr "cpu" "rs64a,mpccore,ppc403,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc750")) (eq_attr "cpu" "rs64a,mpccore,ppc403,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc750"))
4 1) 4 1)
(define_function_unit "bpu" 1 0
(and (eq_attr "type" "cr_logical")
(eq_attr "cpu" "ppc604,ppc620"))
4 1)
(define_function_unit "cru" 1 0
(and (eq_attr "type" "cr_logical")
(eq_attr "cpu" "ppc604e"))
4 1)
; all jumps/branches are executing on the bpu, in 1 cycle, for all machines. ; all jumps/branches are executing on the bpu, in 1 cycle, for all machines.
(define_function_unit "bpu" 1 0 (define_function_unit "bpu" 1 0
(eq_attr "type" "jmpreg") (eq_attr "type" "jmpreg")
...@@ -9847,270 +9872,94 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); ...@@ -9847,270 +9872,94 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
}") }")
(define_expand "beq" (define_expand "beq"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (eq (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (EQ, operands[0]); DONE; }")
{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
operands[1] = gen_rtx_COMPARE (mode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
}")
(define_expand "bne" (define_expand "bne"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (ne (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (NE, operands[0]); DONE; }")
{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
operands[1] = gen_rtx_COMPARE (mode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
}")
(define_expand "blt" (define_expand "bge"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (lt (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (GE, operands[0]); DONE; }")
{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
operands[1] = gen_rtx_COMPARE (mode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
}")
(define_expand "bgt" (define_expand "bgt"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (gt (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (GT, operands[0]); DONE; }")
{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
operands[1] = gen_rtx_COMPARE (mode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
}")
(define_expand "ble" (define_expand "ble"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (le (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (LE, operands[0]); DONE; }")
{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
operands[1] = gen_rtx_COMPARE (mode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
}")
(define_expand "bge" (define_expand "blt"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (ge (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (LT, operands[0]); DONE; }")
{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
operands[1] = gen_rtx_COMPARE (mode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
}")
(define_expand "bgtu" (define_expand "bgeu"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (gtu (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (GEU, operands[0]); DONE; }")
{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCUNSmode);
}")
(define_expand "bltu" (define_expand "bgtu"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (ltu (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (GTU, operands[0]); DONE; }")
{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCUNSmode);
}")
(define_expand "bgeu" (define_expand "bleu"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (geu (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (LEU, operands[0]); DONE; }")
{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCUNSmode);
}")
(define_expand "bleu" (define_expand "bltu"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (leu (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (LTU, operands[0]); DONE; }")
{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCUNSmode);
}")
(define_expand "bunordered" (define_expand "bunordered"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (unordered (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (UNORDERED, operands[0]); DONE; }")
{ if (!rs6000_compare_fp_p) FAIL;
operands[1] = gen_rtx_COMPARE (CCFPmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCFPmode);
}")
(define_expand "bordered" (define_expand "bordered"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (ordered (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (ORDERED, operands[0]); DONE; }")
{ if (!rs6000_compare_fp_p) FAIL;
operands[1] = gen_rtx_COMPARE (CCFPmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCFPmode);
}")
(define_expand "buneq" (define_expand "buneq"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (uneq (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (UNEQ, operands[0]); DONE; }")
{ if (!rs6000_compare_fp_p) FAIL;
operands[1] = gen_rtx_COMPARE (CCFPmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCFPmode);
}")
(define_expand "bunge" (define_expand "bunge"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (unge (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (UNGE, operands[0]); DONE; }")
{ if (!rs6000_compare_fp_p) FAIL;
operands[1] = gen_rtx_COMPARE (CCFPmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCFPmode);
}")
(define_expand "bungt" (define_expand "bungt"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (ungt (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (UNGT, operands[0]); DONE; }")
{ if (!rs6000_compare_fp_p) FAIL;
operands[1] = gen_rtx_COMPARE (CCFPmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCFPmode);
}")
(define_expand "bunle" (define_expand "bunle"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (unle (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (UNLE, operands[0]); DONE; }")
{ if (!rs6000_compare_fp_p) FAIL;
operands[1] = gen_rtx_COMPARE (CCFPmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCFPmode);
}")
(define_expand "bunlt" (define_expand "bunlt"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (unlt (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (UNLT, operands[0]); DONE; }")
{ if (!rs6000_compare_fp_p) FAIL;
operands[1] = gen_rtx_COMPARE (CCFPmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCFPmode);
}")
(define_expand "bltgt" (define_expand "bltgt"
[(set (match_dup 2) (match_dup 1)) [(use (match_operand 0 "" ""))]
(set (pc)
(if_then_else (ltgt (match_dup 2)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
"" ""
" "{ rs6000_emit_cbranch (LTGT, operands[0]); DONE; }")
{ if (!rs6000_compare_fp_p) FAIL;
operands[1] = gen_rtx_COMPARE (CCFPmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCFPmode);
}")
;; For SNE, we would prefer that the xor/abs sequence be used for integers. ;; For SNE, we would prefer that the xor/abs sequence be used for integers.
;; For SEQ, likewise, except that comparisons with zero should be done ;; For SEQ, likewise, except that comparisons with zero should be done
...@@ -10118,261 +9967,85 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); ...@@ -10118,261 +9967,85 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
;; resulting insns, we must, in fact, allow SEQ for integers. Fail in ;; resulting insns, we must, in fact, allow SEQ for integers. Fail in
;; the cases we don't want to handle. ;; the cases we don't want to handle.
(define_expand "seq" (define_expand "seq"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(eq:SI (match_dup 2) (const_int 0)))]
"" ""
" "{ rs6000_emit_sCOND (EQ, operands[0]); DONE; }")
{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
operands[1] = gen_rtx_COMPARE (mode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_EQ (DImode, operands[2], const0_rtx), 0);
DONE;
}
}")
(define_expand "sne" (define_expand "sne"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(ne:SI (match_dup 2) (const_int 0)))]
"" ""
" "
{ if (! rs6000_compare_fp_p) {
if (! rs6000_compare_fp_p)
FAIL; FAIL;
operands[1] = gen_rtx_COMPARE (CCFPmode, rs6000_emit_sCOND (NE, operands[0]);
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCFPmode);
if (TARGET_POWERPC64)
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_NE (DImode, operands[2], const0_rtx), 0);
DONE; DONE;
}
}") }")
;; A > 0 is best done using the portable sequence, so fail in that case. ;; A > 0 is best done using the portable sequence, so fail in that case.
(define_expand "sgt" (define_expand "sgt"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(gt:SI (match_dup 2) (const_int 0)))]
"" ""
" "
{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode; {
if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx) if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
FAIL; FAIL;
operands[1] = gen_rtx_COMPARE (mode, rs6000_emit_sCOND (GT, operands[0]);
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_GT (DImode, operands[2], const0_rtx), 0);
DONE; DONE;
}
}") }")
;; A < 0 is best done in the portable way for A an integer. ;; A < 0 is best done in the portable way for A an integer.
(define_expand "slt" (define_expand "slt"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(lt:SI (match_dup 2) (const_int 0)))]
"" ""
" "
{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode; {
if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx) if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
FAIL; FAIL;
operands[1] = gen_rtx_COMPARE (mode, rs6000_emit_sCOND (LT, operands[0]);
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_LT (DImode, operands[2], const0_rtx), 0);
DONE; DONE;
}
}") }")
(define_expand "sge" (define_expand "sge"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(ge:SI (match_dup 2) (const_int 0)))]
"" ""
" "{ rs6000_emit_sCOND (GE, operands[0]); DONE; }")
{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
operands[1] = gen_rtx_COMPARE (mode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_GE (DImode, operands[2], const0_rtx), 0);
DONE;
}
}")
;; A <= 0 is best done the portable way for A an integer. ;; A <= 0 is best done the portable way for A an integer.
(define_expand "sle" (define_expand "sle"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(le:SI (match_dup 2) (const_int 0)))]
"" ""
" "
{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode; {
if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx) if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
FAIL; FAIL;
operands[1] = gen_rtx_COMPARE (mode, rs6000_emit_sCOND (LE, operands[0]);
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (mode);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_LE (DImode, operands[2], const0_rtx), 0);
DONE; DONE;
}
}") }")
(define_expand "sgtu" (define_expand "sgtu"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(gtu:SI (match_dup 2) (const_int 0)))]
"" ""
" "{ rs6000_emit_sCOND (GTU, operands[0]); DONE; }")
{ enum machine_mode op_mode;
operands[1] = gen_rtx_COMPARE (CCUNSmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCUNSmode);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && op_mode == DImode)
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_GTU (DImode, operands[2], const0_rtx), 0);
DONE;
}
}")
(define_expand "sltu" (define_expand "sltu"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(ltu:SI (match_dup 2) (const_int 0)))]
"" ""
" "{ rs6000_emit_sCOND (LTU, operands[0]); DONE; }")
{ enum machine_mode op_mode;
operands[1] = gen_rtx_COMPARE (CCUNSmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCUNSmode);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && op_mode == DImode)
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_LTU (DImode, operands[2], const0_rtx), 0);
DONE;
}
}")
(define_expand "sgeu" (define_expand "sgeu"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(geu:SI (match_dup 2) (const_int 0)))]
"" ""
" "{ rs6000_emit_sCOND (GEU, operands[0]); DONE; }")
{ enum machine_mode op_mode;
operands[1] = gen_rtx_COMPARE (CCUNSmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCUNSmode);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && op_mode == DImode)
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_GEU (DImode, operands[2], const0_rtx), 0);
DONE;
}
}")
(define_expand "sleu" (define_expand "sleu"
[(set (match_dup 2) (match_dup 1)) [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
(set (match_operand:SI 0 "gpc_reg_operand" "")
(leu:SI (match_dup 2) (const_int 0)))]
"" ""
" "{ rs6000_emit_sCOND (LEU, operands[0]); DONE; }")
{ enum machine_mode op_mode;
operands[1] = gen_rtx_COMPARE (CCUNSmode,
rs6000_compare_op0, rs6000_compare_op1);
operands[2] = gen_reg_rtx (CCUNSmode);
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
op_mode = GET_MODE (rs6000_compare_op1);
if (TARGET_POWERPC64 && op_mode == DImode)
{
emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
convert_move (operands[0],
gen_rtx_LEU (DImode, operands[2], const0_rtx), 0);
DONE;
}
}")
;; Here are the actual compare insns. ;; Here are the actual compare insns.
(define_insn "*cmpsi_internal1" (define_insn "*cmpsi_internal1"
...@@ -10632,38 +10305,6 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); ...@@ -10632,38 +10305,6 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
(const_int 0)))] (const_int 0)))]
"") "")
;; If we are comparing the result of two comparisons, this can be done
;; using creqv or crxor.
(define_insn ""
[(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
(compare:CCEQ (match_operator 1 "scc_comparison_operator"
[(match_operand 2 "cc_reg_operand" "y")
(const_int 0)])
(match_operator 3 "scc_comparison_operator"
[(match_operand 4 "cc_reg_operand" "y")
(const_int 0)])))]
"REGNO (operands[2]) != REGNO (operands[4])"
"*
{
enum rtx_code code1, code2;
code1 = GET_CODE (operands[1]);
code2 = GET_CODE (operands[3]);
if ((code1 == EQ || code1 == LT || code1 == GT
|| code1 == LTU || code1 == GTU
|| (code1 != NE && GET_MODE (operands[2]) == CCFPmode))
!=
(code2 == EQ || code2 == LT || code2 == GT
|| code2 == LTU || code2 == GTU
|| (code2 != NE && GET_MODE (operands[4]) == CCFPmode)))
return \"%C1%C3crxor %E0,%j1,%j3\";
else
return \"%C1%C3creqv %E0,%j1,%j3\";
}"
[(set_attr "length" "12")])
;; There is a 3 cycle delay between consecutive mfcr instructions ;; There is a 3 cycle delay between consecutive mfcr instructions
;; so it is useful to combine 2 scc instructions to use only one mfcr. ;; so it is useful to combine 2 scc instructions to use only one mfcr.
...@@ -13153,7 +12794,7 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); ...@@ -13153,7 +12794,7 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
return output_cbranch (operands[0], NULL, 0, insn); return output_cbranch (operands[0], NULL, 0, insn);
}" }"
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "length" "8")]) (set_attr "length" "4")])
(define_insn "" (define_insn ""
[(set (pc) [(set (pc)
...@@ -13184,7 +12825,112 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); ...@@ -13184,7 +12825,112 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
return output_cbranch (operands[0], NULL, 1, insn); return output_cbranch (operands[0], NULL, 1, insn);
}" }"
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "length" "8")]) (set_attr "length" "4")])
;; Logic on condition register values.
; This pattern matches things like
; (set (reg:CCEQ 68) (compare:CCEQ (ior:SI (gt:SI (reg:CCFP 68) (const_int 0))
; (eq:SI (reg:CCFP 68) (const_int 0)))
; (const_int 1)))
; which are generated by the branch logic.
(define_insn ""
[(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
(compare:CCEQ (match_operator:SI 1 "boolean_operator"
[(match_operator:SI 2
"branch_positive_comparison_operator"
[(match_operand 3
"cc_reg_operand" "y")
(const_int 0)])
(match_operator:SI 4
"branch_positive_comparison_operator"
[(match_operand 5
"cc_reg_operand" "y")
(const_int 0)])])
(const_int 1)))]
""
"cr%q1 %E0,%j2,%j4"
[(set_attr "type" "cr_logical")])
; Why is the constant -1 here, but 1 in the previous pattern?
; Because ~1 has all but the low bit set.
(define_insn ""
[(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
(compare:CCEQ (match_operator:SI 1 "boolean_or_operator"
[(not:SI (match_operator:SI 2
"branch_positive_comparison_operator"
[(match_operand 3
"cc_reg_operand" "y")
(const_int 0)]))
(match_operator:SI 4
"branch_positive_comparison_operator"
[(match_operand 5
"cc_reg_operand" "y")
(const_int 0)])])
(const_int -1)))]
""
"cr%q1 %E0,%j2,%j4"
[(set_attr "type" "cr_logical")])
(define_insn ""
[(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
(compare:CCEQ (match_operator:SI 2
"branch_positive_comparison_operator"
[(match_operand 3
"cc_reg_operand" "y")
(const_int 0)])
(const_int 0)))]
""
"crnot %E0,%j2"
[(set_attr "type" "cr_logical")])
;; If we are comparing the result of two comparisons, this can be done
;; using creqv or crxor.
(define_insn_and_split ""
[(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
(compare:CCEQ (match_operator 1 "branch_comparison_operator"
[(match_operand 2 "cc_reg_operand" "y")
(const_int 0)])
(match_operator 3 "branch_comparison_operator"
[(match_operand 4 "cc_reg_operand" "y")
(const_int 0)])))]
""
"#"
""
[(set (match_dup 0) (compare:CCEQ (xor:SI (match_dup 1) (match_dup 3))
(match_dup 5)))]
"
{
int positive_1, positive_2;
positive_1 = branch_positive_comparison_operator (operands[1], CCEQmode);
positive_2 = branch_positive_comparison_operator (operands[3], CCEQmode);
if (! positive_1)
operands[1] = gen_rtx (SImode,
rs6000_reverse_condition (GET_MODE (operands[2]),
GET_CODE (operands[1])),
operands[2]);
else if (GET_MODE (operands[1]) != SImode)
operands[1] = gen_rtx (SImode,
GET_CODE (operands[1]),
operands[2]);
if (! positive_2)
operands[3] = gen_rtx (SImode,
rs6000_reverse_condition (GET_MODE (operands[4]),
GET_CODE (operands[3])),
operands[4]);
else if (GET_MODE (operands[3]) != SImode)
operands[3] = gen_rtx (SImode,
GET_CODE (operands[3]),
operands[4]);
if (positive_1 == positive_2)
operands[1] = gen_rtx_NOT (SImode, operands[1]);
}")
;; Unconditional branch and return. ;; Unconditional branch and return.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment